60 votes

Validation des champs du modèle Django

Où devrais-la validation du modèle de champs d' aller dans django?

Je pourrais en nommer au moins deux choix possibles: dans la surcharge .méthode save() du modèle ou dans la .to_python() la méthode des modèles.Champ de sous-classe (évidemment, pour que cela fonctionne vous devez écrire des champs personnalisés).

Les cas d'utilisation possibles:

  • lorsque c'est absolument nécessaire afin d'assurer, d'une chaîne vide n'a pas obtenir de l'écrit dans la base de données (vide=False argument mot-clé ne fonctionne pas ici, c'est pour la validation d'un formulaire uniquement)
  • lorsqu'il est nécessaire de s'assurer, que les "choix" argument mot-clé obtient le respect sur un db-niveau, et pas seulement dans l'interface d'administration (genre de l'émulation d'un enum type de données)

Il y a aussi un niveau de classe de l'attribut empty_strings_allowed dans les modèles.Champ de la base de la définition de la classe et les classes dérivées heureux de le remplacer, mais il ne semble pas pour produire un effet sur le niveau de base de données, ce qui signifie que je peut toujours construire un modèle avec vide-champs de type chaîne et l'enregistrer dans la base de données. Je veux éviter (oui, c'est nécessaire).

Implémentations possibles sont

sur le terrain:

class CustomField(models.CharField):
    __metaclass__ = models.SubfieldBase
    def to_python(self, value):
        if not value:
            raise IntegrityError(_('Empty string not allowed'))
        return models.CharField.to_python(self, value)

sur le modèle de niveau:

class MyModel(models.Model)
    FIELD1_CHOICES = ['foo', 'bar', 'baz']
    field1 = models.CharField(max_length=255, 
               choices=[(item,item) for item in FIELD1_CHOICES])

    def save(self, force_insert=False, force_update=False):
        if self.field1 not in MyModel.FIELD1_CHOICES:
            raise IntegrityError(_('Invalid value of field1'))
        # this can, of course, be made more generic
        models.Model.save(self, force_insert, force_update)

Peut-être, je suis en manque de quelque chose et cela peut être fait plus facile (et plus propre)?

65voto

Carl Meyer Points 30736

Django a un modèle de validation du système en place depuis la version 1.2.

Dans les commentaires sebpiq dit "Ok, maintenant, il y a une place pour la validation du modèle ... sauf qu'il est exécuté uniquement lors de l'utilisation d'un ModelForm! Donc, la question reste, lorsqu'il est nécessaire de s'assurer que la validation est respectée à la db-niveau, que devez-vous faire? Où appeler full_clean?"

Il n'est pas possible via Python-niveau de validation pour s'assurer que la validation est respecté sur le niveau en db. Le plus proche est sans doute pour appeler full_clean dans un substituée save méthode. Ce n'est pas fait par défaut, parce qu'il signifie que tout le monde qui appelle à sauver la méthode avait maintenant mieux d'être prêt à attraper et à manipuler ValidationError.

Mais même si vous faites cela, quelqu'un peut toujours mettre à jour les instances de modèle en bloc à l'aide de queryset.update(), ce qui permettra de contourner cette validation. Il n'existe aucun moyen de Django pourrait mettre en œuvre un raisonnablement efficace en queryset.update() qui pourraient encore effectuer Python de validation au niveau de chaque objet mis à jour.

La seule façon de garantir db-niveau d'intégrité est par db-niveau de contraintes, de validation, vous le faites à travers l'ORM exige de l'écrivain de code de l'application pour être au courant lors de la validation est exécutée (et gérer les échecs de validation).

C'est pourquoi la validation du modèle par défaut est appliquée uniquement en ModelForm - parce que, dans un ModelForm il y a déjà un moyen évident de gérer un ValidationError.

7voto

Darius Points 70

Je pense que tu veux ça ->

 from django.db.models.signals import pre_save

def validate_model(sender, **kwargs):
    if 'raw' in kwargs and not kwargs['raw']:
        kwargs['instance'].full_clean()

pre_save.connect(validate_model, dispatch_uid='validate_models')
 

(Copié de http://djangosnippets.org/snippets/2319/ )

3voto

Arthur Debert Points 3632

Le problème de base est que la validation devrait arriver sur les modèles. Ce point a été discuté pendant un certain temps dans django (formulaire de recherche, le modèle de connaissance de validation sur le dev mailing list). Cela conduit soit à la duplication ou les choses s'échapper de validation avant de frapper à la db.

Tout en qui ne touche pas le tronc, Malcolm est "pauvre homme la validation des modèles de solution" est probablement la solution la plus propre pour éviter de vous répéter.

1voto

Oduvan Points 1039

Si je vous comprends bien "clairement" - vous devez écraser la fonction get_db_prep_save au lieu de to_python

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X