从管理内部模型窗体访问父模型实例 [英] Accessing parent model instance from modelform of admin inline

查看:131
本文介绍了从管理内部模型窗体访问父模型实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在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)

#父模型的查找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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆