Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 从admin inline的modelform访问父模型实例_Python_Django_Django Models_Django Forms - Fatal编程技术网

Python 从admin inline的modelform访问父模型实例

Python 从admin inline的modelform访问父模型实例,python,django,django-models,django-forms,Python,Django,Django Models,Django Forms,我在Django的管理中使用了一个表格行,配置为显示一个额外的空白表单 class MyChildInline(admin.TabularInline): model = MyChildModel form = MyChildInlineForm extra = 1 该模型看起来像MyParentModel->MyChildModel->MyInlineForm 我使用的是自定义表单,因此可以动态查找值并填充字段中的选项。e、 g class MyChildInline

我在Django的管理中使用了一个表格行,配置为显示一个额外的空白表单

class MyChildInline(admin.TabularInline):
    model = MyChildModel
    form = MyChildInlineForm
    extra = 1
该模型看起来像MyParentModel->MyChildModel->MyInlineForm

我使用的是自定义表单,因此可以动态查找值并填充字段中的选项。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]
这适用于绑定到实际记录的内联记录,但对于额外的空白表单,它不会在我的选择字段中显示任何值,因为它没有任何记录id,并且无法查找关联的MyParentModel记录


我已经检查了所有可以找到的值(args、kwargs、self.data、self.instance等),但是我找不到任何方法来访问表内联绑定到的父对象。有什么方法可以做到这一点吗?

AdminModel有一些方法,如。它接收一个对象并返回一组表单集。我认为您可以向该表单集类添加一些关于父对象的信息,并在稍后的表单集的

更新中使用它:从Django 1.9开始,在
BaseFormSet
类中有一个
def get\u form\u kwargs(self,index)
方法。因此,将数据传递给表单的重写

这将是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及以下版本:

要将表单集的值传递给各个表单,您必须了解它们是如何构造的。带有“跳转到定义”的编辑器/IDE确实有助于深入了解
ModelAdmin
代码,并了解
inlineformset\u工厂及其
BaseInlineFormSet

从那里你会发现表单是在
\u construct\u 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
是的,这涉及一个私有的
\u构造\u表单
函数


更新注意:这不包括
空表单
,因此您的表单代码需要选择性地接受参数。

对ilvar的答案进行一点扩展,如果感兴趣的表单字段是从模型字段构造的,则可以使用以下构造对其应用自定义行为:

class MyChildInline(admin.TabularInline):
    model = MyChildModel
    extra = 1
    def get_formset(self, request, parent=None, **kwargs):
        def formfield_callback(db_field):
            """
            Constructor of the formfield given the model field.
            """
            formfield = self.formfield_for_dbfield(db_field, request=request)
            if db_field.name == 'my_choice_field' and parent is not None:
                formfield.choices = parent.get_choices()
            return formfield
        return super(MyChildInline, self).get_formset(
            request, obj=obj, formfield_callback=formfield_callback, **kwargs)
        return result

我正在使用Django 1.10,它对我很有效:
创建一个表单集并将父对象放入kwargs:

class MyFormSet(BaseInlineFormSet):

    def get_form_kwargs(self, index):
        kwargs = super(MyFormSet, self).get_form_kwargs(index)
        kwargs.update({'parent': self.instance})
        return kwargs
在调用
super
之前创建一个表单并弹出一个atribute

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

+1,虽然我不确定@Cerin到底想解决什么问题,但大多数情况下,使用通用内联线和formset实例检查contenttype和object_id应该会更容易。我尝试了这一点,但我在MyForm的行中遇到了一个“parent_object”的键错误,在该行中,您尝试弹出parent_对象值。非常好用!确保在调用super之前弹出,并跳过空表单。在Django 1.11中再次测试。很好用。@vdboor,希望你不介意我的编辑。我仔细研究了代码,找到了如何支持
empty\u form
。很高兴看到Django 1.9+解决方案:-)而不是
self.form\u kwargs.copy()
我建议改为调用
super()
。2个问题:1)FormFieldMetaForm是什么?它不应该是超级的(我的形式,自我)?2) 在MyForm.uuu init_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。我编辑这个答案是为了反映Django 1.11的良好性能!