django使用through =和filter_horizo​​ntal管理多对多中介模型

ecb*_*tln 17 django django-models django-admin

这就是我的模型的样子:

class QuestionTagM2M(models.Model):
    tag = models.ForeignKey('Tag')
    question = models.ForeignKey('Question')
    date_added = models.DateTimeField(auto_now_add=True)

class Tag(models.Model):
    description = models.CharField(max_length=100, unique=True)

class Question(models.Model):
    tags = models.ManyToManyField(Tag, through=QuestionTagM2M, related_name='questions')
Run Code Online (Sandbox Code Playgroud)

我真正想做的就是在创建给定的多人关系时添加时间戳.这很有意义,但它也增加了一些复杂性.除了删除.add()功能之外[尽管事实上我真正添加的唯一字段是自动创建的,所以它在技术上不应该再干扰它了].但我可以忍受这一点,因为我不介意做额外的事情,QuestionTagM2M.objects.create(question=,tag=)如果这意味着获得额外的时间戳功能.我的问题是我真的很想能够filter_horizontal在管理员中保存我的javascript小部件.我知道文档说我可以用内联代替,但因为没有其他字段实际上是内联除了外键,这是太笨重Tag反正.此外,在我的数据库模式的更大方案中,我的Question对象已经在我的管理页面上显示为内联,并且由于Django不支持admin [yet]中的嵌套内联,我无法为给定的选择标记题.有没有办法覆盖formfield_for_manytomany(self, db_field, request=None, **kwargs)或类似的东西允许我使用漂亮的filter_horizontal小部件和自动创建date_added列到数据库?这似乎是django应该能够本地执行的东西,只要您指定中间的所有列都是自动创建的(除外键之外)可能与auto_created=True?或类似的东西

okm*_*okm 9

办法做到这一点

  • 由@obsoleter在下面的评论中提供:设置QuestionTagM2M._meta.auto_created = True和处理w/syncdb很重要.
  • 在models.py中动态地将date_added字段添加到模型的M2M模型中Question

    class Question(models.Model):
        # use auto-created M2M model
        tags = models.ManyToMany(Tag, related_name='questions')
    
    
    # add date_added field to the M2M model
    models.DateTimeField(auto_now_add=True).contribute_to_class(
             Question.tags.through, 'date_added')
    
    Run Code Online (Sandbox Code Playgroud)

    然后你可以正常使用它在管理员ManyToManyField.
    在Python shell中,用于Question.tags.through引用M2M模型.

    注意,如果你不使用South,那就syncdb足够了; 如果这样做,South不喜欢这种方式并且不会冻结date_added字段,则需要手动编写迁移以添加/删除相应的列.

  • 自定义ModelAdmin:

    1. 不要fields在自定义的ModelAdmin中定义,只定义filter_horizontal.这将绕过Irfan回答中提到的现场验证.
    2. 自定义formfield_for_dbfield()formfield_for_manytomany()使Django管理员widgets.FilteredSelectMultiple用于该tags字段.
    3. save_related()在ModelAdmin类中自定义方法,比如

def save_related(self, request, form, *args, **kwargs):
    tags = form.cleaned_data.pop('tags', ())
    question = form.instance
    for tag in tags:
        QuestionTagM2M.objects.create(tag=tag, question=question)
    super(QuestionAdmin, self).save_related(request, form, *args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
  • 此外,您可以修补__set__()的的ReverseManyRelatedObjectsDescriptorManyToManyField的现场描述符date_added,以节省M2M例如W/O引发异常.

  • 我通过在`django/contrib/admin/options.py`中读取`BaseModelAdmin.formfield_for_manytomany`方法的源代码找到了另一个选项.您可以通过设置`QuestionTagM2M._meta.auto_created = True来欺骗ModelAdmin使用您的自定义多对多表用于水平/垂直过滤器 (8认同)