django admin 使用 through= 和 filter_horizontal 的多对多中介模型 [英] django admin many-to-many intermediary models using through= and filter_horizontal
问题描述
这是我的模型的外观:
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')
我真正想做的就是在创建给定的多对多关系时添加时间戳.这是有道理的,但它也增加了一些复杂性.除了删除 .add() 功能[尽管我真正添加的唯一字段是自动创建的,因此从技术上讲,它不应再干扰这一点].但我可以接受,因为我不介意做额外的 QuestionTagM2M.objects.create(question=,tag=)
而如果这意味着获得额外的时间戳功能.
All I really wanted to do was add a timestamp when a given manytomany relationship was created. It makes sense, but it also adds a bit of complexity. Apart from removing the .add() functionality [despite the fact that the only field I'm really adding is auto-created so it technically shouldn't interfere with this anymore]. But I can live with that, as I don't mind doing the extra QuestionTagM2M.objects.create(question=,tag=)
instead if it means gaining the additional timestamp functionality.
我的问题是我真的很希望能够在管理员中保留我的 filter_horizontal
javascript 小部件.我知道文档说我可以使用内联代替,但这太笨拙了,因为除了 Tag
的外键之外,实际上没有其他字段可以在内联中.
My issue is I really would love to be able to preserve my filter_horizontal
javascript widget in the admin. I know the docs say I can use an inline instead, but this is just too unwieldy because there are no additional fields that would actually be in the inline apart from the foreign key to the Tag
anyway.
此外,在我的数据库架构的更大方案中,我的 Question
对象已经在我的管理页面上显示为内联,并且因为 Django 不支持在管理中嵌套内联 [尚],我无法为给定的问题选择标签.
Also, in the larger scheme of my database schema, my Question
objects are already displayed as an inline on my admin page, and since Django doesn't support nested inlines in the admin [yet], I have no way of selecting tags for a given question.
有什么方法可以覆盖 formfield_for_manytomany(self, db_field, request=None, **kwargs)
或类似的东西以允许我使用漂亮的 filter_horizontal
小部件以及将 date_ added
列自动创建到数据库中?
Is there any way to override formfield_for_manytomany(self, db_field, request=None, **kwargs)
or something similar to allow for my usage of the nifty filter_horizontal
widget and the auto creation of the date_added
column to the database?
这似乎是 django 应该能够在本机上执行的操作,只要您指定可能使用 auto_created=True
自动创建中间中的所有列(外键除外)?或类似的东西
This seems like something that django should be able to do natively as long as you specify that all columns in the intermediate are automatically created (other than the foreign keys) perhaps with auto_created=True
? or something of the like
推荐答案
有方法可以做到这一点
- 由@obsoleter 在 下面的评论:设置
QuestionTagM2M._meta.auto_created = True
并处理与syncdb有关的事项. 动态添加
date_ added
字段到models.py中Question
模型的M2M模型
- As provided by @obsoleter in the comment below : set
QuestionTagM2M._meta.auto_created = True
and deal w/ syncdb matters. Dynamically add
date_added
field to the M2M model ofQuestion
model in 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 shell 中,使用 Question.tags.through
来引用 M2M 模型.
Then you could use it in admin as normal ManyToManyField
.
In Python shell, use Question.tags.through
to refer the M2M model.
注意,如果不用South
,那么syncdb
就够了;如果你这样做,South
不喜欢这种方式并不会冻结date_ added
字段,您需要手动编写迁移来添加/删除相应的列.
Note, If you don't use South
, then syncdb
is enough; If you do, South
does not like
this way and will not freeze date_added
field, you need to manually write migration to add/remove the corresponding column.
自定义模型管理员:
- 不要在自定义的ModelAdmin中定义
fields
,只定义filter_horizontal
.这将绕过 Irfan 的回答中提到的现场验证. - 自定义
formfield_for_dbfield()
或formfield_for_manytomany()
以使Django 管理员使用widgets.FilteredSelectMultiple
作为标签
> 字段. - 在 ModelAdmin 类中自定义
save_related()
方法,例如
- Don't define
fields
inside customized ModelAdmin, only definefilter_horizontal
. This will bypass the field validation mentioned in Irfan's answer. - Customize
formfield_for_dbfield()
orformfield_for_manytomany()
to make Django admin to usewidgets.FilteredSelectMultiple
for thetags
field. - Customize
save_related()
method inside your ModelAdmin class, like
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)
- 此外,您可以为
date_ added
的 ManyToManyField 的ReverseManyRelatedObjectsDescriptor
字段描述符修补__set__()
以保存不引发异常的 M2M 实例. - Also, you could patch
__set__()
of theReverseManyRelatedObjectsDescriptor
field descriptor of ManyToManyField fordate_added
to save M2M instance w/o raise exception.
这篇关于django admin 使用 through= 和 filter_horizontal 的多对多中介模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!