web-dev-qa-db-fra.com

Django: Supprimer un champ d'une sous-classe Form

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 #??

Existe-t-il un moyen d'y parvenir?

Remarque: je n'ai pas de ModelForm, donc la classe Meta avec exclude ne fonctionne pas.

39
apelliciari

Vous pouvez modifier les champs d'une sous-classe en remplaçant la méthode init:

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

Django 1.7 a résolu ce problème dans commit b16dd1fe019 pour le ticket # 862 . Dans Django 1.7, il devient possible de faire nickname = None dans la sous-classe comme le suggère le PO. D'après les modifications de la documentation dans le commit:

Il est possible de se désengager d'une Field héritée d'une classe parente en l'observant. Bien que toute valeur nonField fonctionne à cet effet, il est recommandé d'utiliser None pour indiquer explicitement qu'un champ est en cours d'annulation.

10
cjerdonek

J'ai trouvé cela, veuillez commenter si vous êtes intéressé.

(dans Django 1.7.4) formulaires étendus, avec le code suivant:

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 définissez field_1 sur None, (la colonne dans db est mise à jour sur Null)

MyForm_Extended_2 ignore le champ (ignore la colonne dans db lors de la sauvegarde)

Donc, pour mon but, j'utilise la deuxième méthode.

5
Gromish

Je n'ai pas aimé le fait (ou du moins j'ai compris) que l'exclusion d'un champ dans la deuxième classe en utilisant "classe Meta:" entraîne toujours le champ inutilisé dans la base de données.

Le moyen le plus simple est peut-être de définir une classe abstraite dont les champs sont partagés par les deux classes. Ensuite, les deux classes originales ci-dessus deviennent des sous-classes de cette nouvelle classe. Ainsi, l'exemple donné au début de ce fil pourrait ressembler à ceci. C'est un peu plus de code, mais de cette façon, vous étendez une sous-classe plutôt que de faire une exclusion (incomplète) d'une super classe.

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
3
Guddo