从管理内部模型窗体访问父模型实例 [英] Accessing parent model instance from modelform of admin inline
问题描述
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)
#父模型的查找ID 。
parent_id =无
如果kwargs中的parent_id:
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]
如果parent_id:
父= MyParentModel.objects.get(id = parent_id)
如果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等),但是我找不到y访问表格内联绑定的父对象的方式。有没有办法这样做?
更新:从Django 1.9开始, def get_form_kwargs(self,index)
方法在 BaseFormSet
类中。因此,覆盖将数据传递给表单。
这将是Python 3 / Django 1.9+版本:
$($)
$ b 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及以下版本:
要将表单的值传递给各个表单,您可以看看它们是如何构建的。一个编辑/ IDE与跳到定义真的有助于在这里深入到$ code> 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)
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 $ b $是的,这涉及私人的 _construct_form
函数。
更新注意:这不包括 empty_form
,因此您的表单代码需要可以接受参数。
I'm using a TabularInline in Django's admin, configured to show one extra blank form.
class MyChildInline(admin.TabularInline):
model = MyChildModel
form = MyChildInlineForm
extra = 1
The model looks like MyParentModel->MyChildModel->MyInlineForm.
I'm using a custom form so I can dynamically lookup values and populate choices in a field. e.g.
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]
This works fine for the inline records bound to an actual record, but for the extra blank form, it doesn't display any values in my choice field, since it doesn't have any record id and there can't lookup the associated MyParentModel record.
I've inspected all the values I could find (args, kwargs, self.data, self.instance, etc) but I can't find any way to access the parent object the tabular inline is bound to. Is there any way to do this?
Update: As of Django 1.9, there is a def get_form_kwargs(self, index)
method in the BaseFormSet
class. Hence, overriding that passes the data to the form.
This would be the Python 3 / Django 1.9+ version:
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
For Django 1.8 and below:
To pass a value of a formset to the individual forms, you'd have to see how they are constructed. An editor/IDE with "jump to definition" really helps here to dive into the ModelAdmin
code, and learn about the inlineformset_factory
and it's BaseInlineFormSet
class.
From there you'll find that the form is constructed in _construct_form()
and you can override that to pass extra parameters. It will likely look something like this:
class MyFormSet(BaseInlineFormSet):
def _construct_form(self, i, **kwargs):
kwargs['parent_object'] = self.instance
return super(MyFormSet, self)._construct_form(i, **kwargs)
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
Yes, this involves a private _construct_form
function.
update Note: This doesn't cover the empty_form
, hence your form code needs to accept the parameters optionally.
这篇关于从管理内部模型窗体访问父模型实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!