web-dev-qa-db-fra.com

Django - Comment spécifier sur quel champ une validation échoue?

J'ai ce modèle que je montre dans la page d'administration:

class Dog(models.Model):
    bark_volume = models.DecimalField(...
    unladen_speed = models.DecimalField(...

    def clean(self):
        if self.bark_volume < 5:
            raise ValidationError("must be louder!")

Comme vous pouvez le voir, j'ai mis une validation sur le modèle. Mais ce que je veux, c'est que la page d'administration affiche l'erreur à côté du champ bark_volume au lieu d'une erreur générale telle qu'elle est maintenant. Existe-t-il un moyen de spécifier sur quel champ la validation échoue?

Merci d'avance.

53
Greg

OK, je l'ai compris à partir de cette réponse .

Vous devez faire quelque chose comme ça:

class Dog(models.Model):
    bark_volume = models.DecimalField(...
    unladen_speed = models.DecimalField(...

    def clean_fields(self):
        if self.bark_volume < 5:
            raise ValidationError({'bark_volume': ["Must be louder!",]})
96
Greg
class Dog(models.Model):
    bark_volume = models.DecimalField(...
    unladen_speed = models.DecimalField(...

    def clean(self):
        if self.bark_volume < 5:
            if not self._errors.has_key('bark_volume'):
                from Django.forms.util import ErrorList
                self._errors['bark_volume'] = ErrorList()
            self._errors['bark_volume'].append('must be louder!')

Cela fonctionne au moins sur les formulaires. Je ne l'ai jamais essayé sur le modèle lui-même, mais la méthodologie devrait être la même. Cependant, à partir des documents Django:

Lorsque vous utilisez un ModelForm, l'appel à is_valid () effectuera ces étapes de validation pour tous les champs inclus dans le formulaire. (Voir la documentation ModelForm pour plus d'informations.) Vous ne devez appeler la méthode full_clean () d'un modèle que si vous prévoyez de gérer vous-même les erreurs de validation ou si vous avez exclu des champs du ModelForm qui nécessitent une validation.

Et...

Notez que full_clean () ne sera pas appelé automatiquement lorsque vous appelez la méthode save () de votre modèle, ni à la suite de la validation ModelForm. Vous devrez l'appeler manuellement lorsque vous souhaitez exécuter la validation du modèle en dehors d'un ModelForm.

Donc, fondamentalement, à moins que vous n'ayez une très bonne raison de nettoyer le champ sur le modèle, vous devez le faire sur le formulaire à la place. Le code pour cela ressemblerait à:

class DogForm(forms.ModelForm):

    def clean(self):
        bark_volume = self.cleaned_data.get('bark_volume')
        if bark_volume < 5:
            if not self._errors.has_key('bark_volume'):
                from Django.forms.util import ErrorList
                self._errors['bark_volume'] = ErrorList()
            self._errors['bark_volume'].append('must be louder!')

        return self.cleaned_data

Et cela fonctionnera, c'est sûr.

12
Chris Pratt

À noter pour tous ceux qui pourraient rencontrer cela avec une version plus récente de Django - la méthode clean_fields de la réponse acceptée nécessite maintenant un paramètre "exclude". Aussi - je crois que la réponse acceptée est également manquante un appel à sa super fonction. Le code final que j'ai utilisé était:

def clean_fields(self, exclude=None):
    super(Model, self).clean_fields(exclude)

    if self.field_name and not self.field_name_required:
        raise ValidationError({'field_name_required':["You selected a field, so field_name_required is required"]})
7
streetlogics

Utiliser un clean_ méthode spécifique au champ:

class DogForm(forms.ModelForm):
    class Meta:
        model = Dog

    def clean_bark_volume(self):
        if self.cleaned_data['bark_volume'] < 5:
            raise ValidationError("must be louder!")

Voir le clean<fieldname> partie de la page Validation du formulaire . Assurez-vous également d'utiliser cleaned_data au lieu du champ de formulaire lui-même; ces derniers peuvent avoir d'anciennes données. Enfin, faites-le sur le formulaire et non sur le modèle.

6
Mike DeSimone

La manière la plus simple de valider ce cas particulier serait:

from Django.core.validators import MinValueValidator
from Django.utils.translation import ugettext_lazy as _

class Dog(models.Model):
    bark_volume = models.DecimalField(
        ..., validators=[MinValueValidator(5, message=_("Must be louder!"))]

Documentation de Django sur les validateurs: https://docs.djangoproject.com/en/dev/ref/validators/

4
Monika Sulik

en abrégé, à partir des documents Django :

def clean(self):
    data = self.cleaned_data
    subject = data.get("subject")

    if subject and "help" not in subject:
        msg = "Must put 'help' in subject."
        self.add_error('subject', msg)

    return data
2
Chase