我在Django的管理员中使用TabularInline,配置为显示一个额外的空白表单。
class MyChildInline(admin.TabularInline):
model = MyChildModel
form = MyChildInlineForm
extra = 1
模型看起来像MyParentModel-> MyChildModel-> MyInlineForm。
我正在使用自定义表单,因此我可以动态查找值并填充字段中的选项。例如
class MyChildInlineForm(ModelForm):
my_choice_field = forms.ChoiceField()
def __init__(self, *args, **kwargs):
super(MyChildInlineForm, self).__init__(*args, **kwargs)
# Lookup ID of parent model.
parent_id = None
if "parent_id" in kwargs:
parent_id = kwargs.pop("parent_id")
elif self.instance.parent_id:
parent_id = self.instance.parent_id
elif self.is_bound:
parent_id = self.data['%s-parent'% self.prefix]
if parent_id:
parent = MyParentModel.objects.get(id=parent_id)
if rev:
qs = parent.get_choices()
self.fields['my_choice_field'].choices = [(r.name,r.value) for r in qs]
这适用于绑定到实际记录的内联记录,但对于额外的空白表单,它不会在我的选择字段中显示任何值,因为它没有任何记录ID且无法查找关联的MyParentModel记录。
我已经检查了所有可以找到的值(args,kwargs,self.data,self.instance等),但我找不到任何方法来访问表格内联绑定的父对象。有没有办法做到这一点?
答案 0 :(得分:24)
更新:从Django 1.9开始,def get_form_kwargs(self, index)
类中有一个BaseFormSet
方法。因此,覆盖将数据传递给表单。
这将是Python 3 / Django 1.9+版本:
class MyFormSet(BaseInlineFormSet):
def get_form_kwargs(self, index):
kwargs = super().get_form_kwargs(index)
kwargs['parent_object'] = self.instance
return kwargs
class MyForm(forms.ModelForm):
def __init__(self, *args, parent_object, **kwargs):
self.parent_object = parent_object
super(MyForm, self).__init__(*args, **kwargs)
class MyChildInline(admin.TabularInline):
formset = MyFormSet
form = MyForm
对于Django 1.8及以下版本:
要将formset的值传递给各个表单,您必须查看它们是如何构造的。具有“跳转到定义”的编辑器/ IDE确实有助于深入了解ModelAdmin
代码,并了解inlineformset_factory
及其BaseInlineFormSet
类。
从那里你会发现表单是在_construct_form()
中构建的,你可以覆盖它以传递额外的参数。它可能看起来像这样:
class MyFormSet(BaseInlineFormSet):
def _construct_form(self, i, **kwargs):
kwargs['parent_object'] = self.instance
return super(MyFormSet, self)._construct_form(i, **kwargs)
@property
def empty_form(self):
form = self.form(
auto_id=self.auto_id,
prefix=self.add_prefix('__prefix__'),
empty_permitted=True,
parent_object=self.instance,
)
self.add_fields(form, None)
return form
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.parent_object = kwargs.pop('parent_object', None)
super(MyForm, self).__init__(*args, **kwargs)
class MyChildInline(admin.TabularInline):
formset = MyFormSet
form = MyForm
是的,这涉及私人_construct_form
功能。
更新注意:这不包括empty_form
,因此您的表单代码需要选择接受这些参数。
答案 1 :(得分:4)
我使用的是Django 1.10,它对我有用:
创建一个FormSet并将父对象放入kwargs:
super
创建表单并在class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
parent = kwargs.pop('parent')
super(MyForm, self).__init__(*args, **kwargs)
# do whatever you need to with parent
调用
class MyModelInline(admin.StackedInline):
model = MyModel
fields = ('my_fields', )
form = MyFrom
formset = MyFormSet
将其放入内联管理员:
SecurityUtils.getCurrentUserLogin()
答案 2 :(得分:1)
AdminModel有一些方法,如get_formsets。它接收一个对象并返回一堆表单集。我想你可以将一些关于父对象的信息添加到那个formset类中,稍后在formset的__init __
中使用它答案 3 :(得分:1)
扩展ilvar的回答,如果感兴趣的表单字段是从模型字段构造的,则可以使用以下构造对其应用自定义行为:
{
data: {
id: 'test',
type: 'foo-detail',
attributes: {
image: '/testimage.jpg'
}
}
}