93 votes

Comment créer un champ flottant Django avec des limites maximales et minimales ?

Je stocke des données en virgule flottante dans mes modèles Django, et seule une certaine plage de valeurs est significative. Par conséquent, j'aimerais imposer ces limites au niveau du modèle et des contraintes SQL.

Par exemple, j'aimerais faire quelque chose comme ceci :

class Foo(Model):
   myfloat = FloatField(min=0.0, max=1.0)

Je veux le faire au niveau du modèle, pas au niveau du formulaire. En fait, je pourrais souhaiter que le niveau du formulaire ait une plage différente ; par exemple, utiliser des pourcentages [0,100] au niveau du formulaire, mais les traduire en [0,1] dans le modèle.

Est-ce possible et, dans l'affirmative, comment dois-je m'y prendre ?

163voto

dfrankow Points 2983

Les réponses données jusqu'à présent décrivent comment faire valider les formulaires. Vous pouvez également placer des validateurs dans le modèle. Utiliser Valideur de valeur minimale y Valideur de valeur maximale .

Par exemple :

from django.core.validators import MaxValueValidator, MinValueValidator

...
weight = models.FloatField(
    validators=[MinValueValidator(0.0), MaxValueValidator(1.0)],
)

EDIT :

Cependant, cela n'ajoute pas de contrainte SQL.

Vous pouvez ajouter des contraintes SQL comme décrit aquí como CheckConstraint en Meta.constraints .

Exemple combiné :

from django.core.validators import MaxValueValidator, MinValueValidator
from django.db.models import CheckConstraint, Q

class Foo(Model):
    myfloat = FloatField(min=0.0, max=1.0,
        # for checking in forms
        validators=[MinValueValidator(0.0), MaxValueValidator(1.0)],)

    class Meta:
        constraints = (
            # for checking in the DB
            CheckConstraint(
                check=Q(myfloat__gte=0.0) & Q(myfloat__lte=1.0),
                name='foo_myfloat_range'),
            )

22voto

San4ez Points 4184

Si vous avez besoin d'une contrainte au niveau du formulaire, vous pouvez passer le paramètre min_value y max_value a champ du formulaire :

myfloat = forms.FloatField(min_value=0.0, max_value=1.0)

Mais si vous devez passer au niveau du modèle, vous devez étendre la base. models.FloatField classe

class MinMaxFloat(models.FloatField):
    def __init__(self, min_value=None, max_value=None, *args, **kwargs):
        self.min_value, self.max_value = min_value, max_value
        super(MinMaxFloat, self).__init__(*args, **kwargs)

    def formfield(self, **kwargs):
        defaults = {'min_value': self.min_value, 'max_value' : self.max_value}
        defaults.update(kwargs)
        return super(MinMaxFloat, self).formfield(**defaults)

Vous pouvez ensuite l'utiliser dans des modèles

class Foo(models.Model):
    myfloat = MinMaxFloat(min_value=0.0, max_value=1.0)

1voto

Gr3at Points 74

Cela fait un certain temps et la réponse votée par la communauté est assez bonne, basée sur les modules intégrés de Django, mais voici une autre approche, spécifique au problème, qui suit la méthode Documentation du projet Django .

Créer un validateur personnalisé

# app/models.py or create another file for custom validators, i.e. app/custom_validators.py
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _  # use if you support internationalization

def validate_interval(value):
    if value < 0.0 or value > 1.0:
        raise ValidationError(_('%(value)s must be in the range [0.0, 1.0]'), params={'value': value},)

Utilisez votre validateur dans vos modèles

# app/models.py

class Foo(models.Model):
    myfloat = models.FloatField(validators=[validate_interval])

Vous pouvez même rendre le validateur paramétrique pour qu'il soit plus générique.

EDIT - IMPORTANT

Il faut garder à l'esprit que tout validateur est invoqué pendant la phase d'élaboration du formulaire. clean() méthode.

Par exemple, si vous essayez de créer directement un objet sans utiliser de formulaire, votre validateur va PAS soit invoquée.

Certains ne le recommandent pas, mais si vous souhaitez invoquer des validateurs lors de la création d'un objet, remplacez la méthode save.

# app/models.py

from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _  # use if you support internationalization

class Foo(models.Model):
    def save(self, *args, **kwargs):
        self.full_clean()  # or clean
        super().save(*args, **kwargs)

    def validate_interval(value):
        if value < 0.0 or value > 1.0:
            raise ValidationError(_('%(value)s must be in the range [0.0, 1.0]'), params={'value': value},)

    myfloat = models.FloatField(validators=[validate_interval])

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