如何子类化 modelform(从模型扩展额外字段)?

4 投票
3 回答
3031 浏览
提问于 2025-04-16 20:37

我有一个模型和一个表单:

class MyModel(models.Model):
    field_foo = models.CharField(_("Foo"), max_length=50)
    field_bar = models.IntegerField(_("Bar"))

class MyFormOne(forms.ModelForm):
    class Meta:
        model=MyModel
        fields = ('field_foo', )
        widgets = {'field_foo': forms.TextInput(attrs={'size': 10, 'maxlength': 50}),}

我想要再创建一个表单 MyFormTwo,这个表单要在原有表单的基础上增加一个字段 field_bar。我的目的是为了避免在第二个表单中重复声明 field_foo 这个控件(遵循DRY原则),而且也不想在 MyFormOne 中重复列出字段(实际上,字段的数量比上面这个简单的例子要多得多)。

我应该怎么定义 MyFormTwo 呢?

3 个回答

0

这个代码片段有点老了,但它解释了我唯一能让多重继承工作的方法。说实话,这个方法看起来挺丑陋的。

http://djangosnippets.org/snippets/703/

关于这个问题,还有一个开放的工单:https://code.djangoproject.com/ticket/7018

3

我不确定这个方法是否有效(我还没有在Django的表单或模型上测试过),不过如果有效的话请告诉我。

class MyModel(models.Model):
    field_foo = models.CharField(_("Foo"), max_length=50)
    field_bar = models.IntegerField(_("Bar"))

class MyFormOne(forms.ModelForm):
    class Meta:
        model=MyModel
        fields = ('field_foo', )
        widgets = {'field_foo': forms.TextInput(attrs={'size': 10, 'maxlength': 50}),}

class MyFormTwo(MyFormOne):
    class Meta(MyFormOne.Meta):
        fields = MyFormOne.Meta.fields + ('field_foo2',)
        widgets = MyFormOne.Meta.widgets
        # Add new fields as a dictionary
        widgets.update({'field_foo2': forms.TextInput(attrs={'size': 10, 'maxlength': 50}),)
        # Or add them one by one
        widgets['field_foo3'] = forms.TextInput(attrs={'size': 10, 'maxlength': 50})

再说一次,我也不知道这是否能帮到你。请告诉我你得到的结果。

4

你不需要完全声明整个小部件,只需要修改那些不同的属性就可以了。或者,如果你在实际代码中有自定义的小部件,我会选择以下两种方法:

  1. 创建一个自定义的模型字段类,这个类默认使用那个小部件,如果这是一个通用的情况,那么在表单类中它就会“自动”工作。
  2. 如果只是针对表单的特定情况(而不是模型特定),那么我会在表单类中明确声明表单字段,而不是在Meta中,这样继承就会以简单明了的方式应用。

但是对于默认的小部件(带有自定义属性),我会尝试以下方法:

class MyModel(models.Model):
    field_foo = models.CharField(_("Foo"), max_length=50)
    field_bar = models.IntegerField(_("Bar"))

class MyFormOne(forms.ModelForm):
    class Meta:
        model=MyModel
        fields = ('field_foo', )

    def __init__(*args, **kwargs):
        super(MyFormOne, self).__init__(*args, **kwargs)

        self.fields['field_foo'].widget.attrs['size'] = 10
        # max_length should already be set automatically from model
        # TextInput is also default widget for CharField

class MyFormTwo(MyFormOne):
    class Meta:
        model=MyModel
        fields = MyFormOne.Meta.fields + ('field_foo2',)

    def __init__(*args, **kwargs):
        super(MyFormTwo, self).__init__(*args, **kwargs)

        self.fields['field_foo2'].widget.attrs['size'] = 10

撰写回答