如何在Django表单中排除继承的字段?

9 投票
3 回答
5103 浏览
提问于 2025-04-16 14:07

我有一个表单和一个继承的表单:

class UsuarioAdminForm(ModelForm):

    first_name = forms.CharField(label='Nombre', help_text = 'Nombre del usuario', required=True)
    last_name = forms.CharField(label='Apellidos', help_text = 'Apellidos del usuario', required=True)
    dni = ESIdentityCardNumberField(help_text = 'DNI del usuario', required=True, widget = forms.TextInput(attrs = {'size': 9}))
    username = forms.CharField(label='Login', help_text = 'Requerido. 30 caracteres o menos. Letras, números y @/./+/-/_', widget = forms.TextInput(attrs = {'size': 15}))
    #password = forms.CharField(widget=forms.PasswordInput(attrs = {'size': 12}), label='Contraseña', help_text = 'Contraseña del usuario')
    email = forms.EmailField(help_text = 'Correo electrónico del usuario', required=True)
    movil = ESPhoneNumberField(help_text = 'Movil principal del usuario', required=True, widget = forms.TextInput(attrs = {'size': 9 }))
    is_staff = forms.BooleanField(label = "Administrador", help_text = 'Marque la casilla si desea crear un administrador')
    tipo_u = forms.ChoiceField(label = 'Tipo de usuario', choices = TipoUsuarios)
    def clean(self):
        try:
            cleaned_data = self.cleaned_data
            movil = self.cleaned_data['movil']
            dni = self.cleaned_data['dni']
            email = self.cleaned_data['email']
        except:
            raise forms.ValidationError(u'Todos los campos del Formulario son Obligatorios.')

        return cleaned_data

    class Meta:
        model = Usuario
        exclude = ('is_active','date_joined', 'last_login', 'user_permissions', 'tipo', 'groups', 'is_superuser', )


class UsuarioForm(UsuarioAdminForm):

    is_staff = None

    def __init__(self, *args, **kwargs):
        self.is_staff = None
        super(UsuarioForm,self).__init__(*args, **kwargs)

    class Meta:
        model = Usuario
        exclude = ('is_staff', 'is_active','date_joined', 'last_login', 'user_permissions', 'tipo', 'groups', 'is_superuser', 'password', )

但是当我创建一个 UsuarioForm 对象时,为什么会显示 is_staff 这个字段呢?

更新:

如果我写 self.fields['is_staff'] = None,我会得到下面的错误:

在 /sms/usuarios/add/user/ 出现了 TemplateSyntaxError

渲染时捕获到 AttributeError:'NoneType' 对象没有 'label' 这个属性

3 个回答

-1

Django 的表单实例会把字段存储在表单本身的 'fields' 属性里。所以在你的 init 方法里,在调用父类的方法之后,你需要做一些类似下面的事情:

self.fields['is_staff'] = None

这样应该能解决你的问题;设置 self.is_staff 只是一个无关的变量(你在类上设置的 is_staff 是类变量,而不是实例变量)。

3

这是一个老问题,但从Django 1.7.x开始,你可以直接这样做:

class UsuarioForm(UsuarioAdminForm):

    is_staff = None

    class Meta:
        model = Usuario
        exclude = ('is_active', 'date_joined', 'last_login', 'user_permissions', 'tipo', 'groups', 'is_superuser', 'password')

Meta中的exclude部分只是用来排除ModelForm中的元素,但任何表单元素都可以通过在声明中将其设置为None来排除。

根据Django文档关于表单继承的说明

可以通过在子类中将字段名设置为None,来声明性地移除从父类继承的字段。例如:

>>> from django import forms

>>> class ParentForm(forms.Form):
...     name = forms.CharField()
...     age = forms.IntegerField()

>>> class ChildForm(ParentForm):
...     name = None

>>> ChildForm().fields.keys()
... ['age']

编辑

我觉得上面的做法在给出的例子中是有效的,但对于那些由于MetaModelForm中创建的字段,似乎就不太管用了。我认为在这种情况下,你需要从父类的Meta继承,并修改给定的字段。

11

也许你可以调整一下这些代码的顺序:

def __init__(self, *args, **kwargs):
    super(UsuarioForm,self).__init__(*args, **kwargs)        
    self.is_staff = None

你也可以这样做:

def __init__(self, *args, **kwargs):
    super(UsuarioForm,self).__init__(*args, **kwargs)
    self.fields.pop('is_staff')

撰写回答