许多到许多中介机型通过使用Django管理=和filter_horizo​​ntal(django

2019-06-23 13:13发布

这是我的模型的外观:

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')

我真正希望做的是增加一个时间戳创建一个给定的多对多关系时。 这是有道理的,但同时也增加了一点复杂性。 除了[尽管只有场我真的是添加自动创建的,因此在技术上不应该干涉这个再也]取出。新增()功能。 但我可以忍受,因为我不介意做额外的QuestionTagM2M.objects.create(question=,tag=) ,而不是它是否意味着获得了另外的时间戳功能。 我的问题是,我真的很想能够保持自己的filter_horizontal的JavaScript小部件的管理。 我知道文档说我可以用内联代替,但因为没有其他字段实际上是内联除了外键,这是太笨重Tag反正。 此外,在我的数据库架构的更大的计划,我的Question对象已经显示为我的管理页面上内联,由于Django不支持嵌套的内嵌在admin [但]我没有选择标签的方式给定的问题。 有没有什么办法来覆盖formfield_for_manytomany(self, db_field, request=None, **kwargs)或类似允许我对漂亮的东西使用filter_horizontal配件和自动创建的date_added列到数据库? 这似乎像Django的应该是能够做到本身,只要你指定在中间的所有列自动创建的(而不是外键等)的东西也许auto_created=True ? 或类似的东西

Answer 1:

办法做到这一点

  • 正如@obsoleter中提供下面的评论 :设定QuestionTagM2M._meta.auto_created = True和交易W /执行syncdb事项。
  • 动态添加date_added领域的M2M模型Question模型在models.py

     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') 

    然后,你可以在管理员使用它作为正常ManyToManyField
    在Python外壳,使用Question.tags.through指的M2M模型。

    请注意 ,如果你不使用South ,然后syncdb就够了; 如果你这样做, South不喜欢这种方式,也不会冻结date_added领域,你需要手动编写迁移到添加/删除相应的列。

  • 自定义的ModelAdmin:

    1. 不要定义fields定制的ModelAdmin内,只定义filter_horizontal 。 这将绕过在伊尔凡的回答中提到的现场验证。
    2. formfield_for_dbfield()formfield_for_manytomany()使Django管理使用widgets.FilteredSelectMultipletags领域。
    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)
  • 此外,您可以修补__set__()ReverseManyRelatedObjectsDescriptor ManyToManyField领域描述符date_added节省M2M例如W / O引发异常。


Answer 2:

该文档可能已经改变,因为以前的答案被张贴。 我接过一看Django文档链接@Irfan提到,它似乎是一个更直接的则曾经是。

内嵌类添加到您的admin.py和模型设置为您的M2M模型

class QuestionTagM2MInline(admin.TabularInline):
    model = QuestionTagM2M
    extra = 1

inlines在你的管理类包含内嵌刚刚定义

class QuestionAdmin(admin.ModelAdmin):
    #...other stuff here
    inlines = (QuestionTagM2MInline,)

不要忘记注册该管理类

admin.site.register(Question, QuestionAdmin)

做好以上后,当我一个问题,我有如下形式做在我的m2m关系的元素列表上它和下面的所有普通编辑,请点击这里,我可以添加条目或编辑现有的。



Answer 3:

从https://docs.djangoproject.com/en/dev/ref/contrib/admin/#working-with-many-to-many-intermediary-models

当你使用一个ManyToManyField的通过参数指定的中介模式,管理员不会默认显示的Widget。 这是因为,中间模型的每个实例需要比在单个窗口小部件可以显示更多的信息,并且将根据所述中间模型变化所需的多个部件的布局。

但是,您可以尝试使用包括标签领域明确fields = ('tags',)在管理。 这将导致该验证异常

“QuestionAdmin.fields”可以不包括ManyToManyField字段“标签”,因为“代码”手动指定a“到”模型。

此验证实现https://github.com/django/django/blob/master/django/contrib/admin/validation.py#L256

        if isinstance(f, models.ManyToManyField) and not f.rel.through._meta.auto_created:
            raise ImproperlyConfigured("'%s.%s' "
                "can't include the ManyToManyField field '%s' because "
                "'%s' manually specifies a 'through' model." % (
                    cls.__name__, label, field, field))

我不认为,除非你实现自己的自定义字段作为ManyToManyField就可以绕过这个验证。



文章来源: django admin many-to-many intermediary models using through= and filter_horizontal