我们想在Django管理员的基本“添加”或“更改”页面上设置代表不同种类模型关系的选择框的初始选择。 如果用户单击“保存”按钮之一,则初始选择应保存到数据库中。
我们特别想通过在表单字段(对于initial
或ModelAdmin
)上设置TabularInline
值来做到这一点。
问题是:
为不同类型的关系表单域分配给 {em> Field.initial
,的正确“值”是什么?
假设我们有一个简单的Model
,其中有一个或多个 relationship fields,即OneToOneField
,ForeignKey
或ManyToManyField
。默认情况下,后者具有隐式 through
模型,但也可以使用 explicit through
模型,如{{3 }}。显式through
模型是具有docs两个ForeignKey
字段的模型。
由选择框表示的关系字段自动显示在标准ModelAdmin
“添加”或“更改”表单上,但带有显性 {{ {1}}模型。如文档at least所述,该代码需要内联,例如ManyToManyField
。
请注意,隐式 through
与(admin)表单上的TabularInline
关联,而其他关系字段也与ManyToManyField
关联。后者包括具有显式 ModelMultipleChoiceField
模型的ModelChoiceField
,因为它实际上由ManyToManyField
中的through
字段表示。
现在考虑此模型的基本Django ForeignKey
“添加”(或“更改”)页面,包括任何 explicit TabularInline
模型的内联。下面是一个基于Django的Pizza-Topping的示例。
我们要实现两个目标:
请注意,第二个看似微不足道,但显然不是(见下文)。
据我所知,有几种方法可以实现这一目标:
无论哪种方法在特定用例中都是“最佳”,这个问题是关于最后一种方法:设置Form.initial
的值。 / p>
我们通过扩展Field.initial
(或Field.initial
)来做到这一点,如下所示:
ModelAdmin.formfield_for_dbfield
此示例中的TabularInline.formfield_for_dbfield
可以是def formfield_for_dbfield(self, db_field, request, **kwargs):
if db_field.name == 'some_relationship_field_name':
kwargs['initial'] = value
return super().formfield_for_dbfield(db_field, request, **kwargs)
,value
,obj.id
或obj
,其中[obj.id, ...]
是{{ 1}}实例。
根据关系字段的类型,不同类型的[obj, ...]
可能会或可能不会。
对于具有隐式obj
模型的Model
,我们只能分配一个对象列表,这样很容易。
对于其他关系,在某些情况下,初始选择框选择与分配的值匹配,但未保存(例如,因为docs返回value
)。
在其他情况下,将保存初始选择框值,但与分配的值不匹配。
因此,显而易见的问题是:
对于管理表单上不同类型的关系字段,应将ManyToManyField
分配给through
的正确方法是什么?
尽管花了很多时间进行搜索,但我在文档中,SO或其他任何地方都找不到清晰的答案。还试图通过源代码来解决这个问题,但这确实很棘手。
一些类似的问题:
答案 0 :(得分:0)
下表显示了使用Django 2.1的一些最小的专用示例的实验结果。根据该表,看起来:
obj
或obj.id
仅适用于OneToOneField
和ForeignKey
[obj.id]
适用于ModelChoiceField
[obj]
仅适用于由ManyToManyField
表示的隐式ModelMultipleChoiceField
但是,我不能说每种情况下预期的处理方式。例如,为ForeignKey
字段分配列表没有多大意义。但是,有趣的是,即使具有显式ManyToManyField
模型的through
内联了ModelChoiceField
的{{1}},我们也不能只分配{{1 }}或ForeignKey
:它必须在列表中。
任何评论在这里都非常感谢。
表1的关键字:
obj
的值obj.id
(对象不可迭代)Field.initial
(“ int”对象没有属性“ pk”)请注意,我们的所需行为为 1&2 。
表1:为不同关系字段向TypeError
分配不同值的结果
AttributeError