如何在子类中从父表单中移除一个字段?

45
class LoginForm(forms.Form):
    nickname = forms.CharField(max_length=100)
    username = forms.CharField(max_length=100)
    password = forms.CharField(widget=forms.PasswordInput)


class LoginFormWithoutNickname(LoginForm):
    # i don't want the field nickname here
    nickname = None #??

有没有一种方法可以实现这个?

注意:我没有一个ModelForm,所以使用excludeMeta类是不起作用的。

4个回答

79

您可以通过覆盖init方法来更改子类中的字段:

class LoginFormWithoutNickname(LoginForm):
    def __init__(self, *args, **kwargs):
        super(LoginFormWithoutNickname, self).__init__(*args, **kwargs)
        self.fields.pop('nickname')

谢谢, 请将 __init__(self) 编辑为 __init__(self, *args, **kwargs) - apelliciari
5
在嵌入的管理表单上无法工作,但模板仍然尝试渲染它们,导致出现KeyError错误。 - lvella

13

在Django 1.7中,修复了b16dd1fe019的提交和#8620票问题。在Django 1.7中,可以像OP建议的那样在子类中执行nickname = None。根据提交的文档更改:

通过遮盖字段可以选择从父类继承的Field退出。虽然任何非Field值都适用于此目的,但建议使用None来明确说明该字段被置空。


这个代码是否有效?因为“nullified”的意思是将取值为None,所以我尝试使用“meta -> exclude = []”可以按照我的预期工作,“你”的方法会使用字段的默认值,即None。 - Gromish
2
请注意,这仅适用于由父类声明的字段。通常,这在“ModelForm”中不起作用。 - SaeX
尝试使用此解决方案来删除TicketForm中的“assigned_to”。该字段已从表单中消失,如预期,但现在在创建Ticket时会抛出错误。默认值已给出,但不在cleaned_data中。有没有一种方法可以隐藏此特定字段,使其仍然通过cleaned_data发送? - T.Nel

5
我发现了这个,请有兴趣的人评论。
(在Django 1.7.4中) 扩展表单,使用以下代码:
class MyForm(forms.ModelForm):

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

        for key, field in self.fields.iteritems():
            self.fields[key].required = False

    class Meta:
        model = MyModel
        exclude = []

    field_1 = forms.CharField(label="field_1_label")
    field_2 = forms.CharField(label="field_2_label", widget=forms.Textarea(attrs={'class': 'width100 h4em'}),)
    field_3 = forms.CharField(label="field_3_label", widget=forms.TextInput(attrs={'class': 'width100'}),)
    field_4 = forms.ModelChoiceField(label='field_4_label', queryset=AnotherModel.objects.all().order_by("order") )

class MyForm_Extended_1(MyForm):
    field_1 = None


class MyForm_Extended_2(MyForm):
    class Meta:
        model = MyModel
        exclude =[
                    'field_1',
                ]

MyForm_Extended_1将field_1设置为None,(数据库中的列将被更新为空)

MyForm_Extended_2忽略该字段(在保存期间忽略数据库中的列)

所以,为了我的目的,我使用第二种方法。


非常有用,也是从表单中删除字段的唯一方法。表单(不带模型) - Alessio

3

我并不喜欢(或者我理解的是)在第二个类中使用“class Meta:”排除一个字段仍然会导致未使用的字段存在于数据库中。

也许最简单的方法是定义一个抽象类,该类具有两个类共享的字段。然后上面的两个原始类成为这个新类的子类。因此,在本帖子开始时给出的示例可能如下所示。代码量有点多,但这种方法是扩展子类而不是从超类中进行(不完整的)排除的方式。

class LoginForm_Common(forms.Form):
    username = forms.CharField(max_length=100)
    password = forms.CharField(widget=forms.PasswordInput)
    class Meta:
        abstract = True

class LoginForm(LoginForm_Common):
    nickname = forms.CharField(max_length=100)

class LoginFormWithoutNickname(LoginForm_Common):
    pass

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接