Hoe een Django floatveld te maken met maximale en minimale limieten?

Ik bewaar een aantal drijvende-puntsgegevens in mijn Django-modellen, en slechts een bepaald aantal waarden zijn zinvol. Daarom wil ik deze limieten opleggen aan zowel het model- als SQL-beperkingsniveau.

Ik wil bijvoorbeeld zoiets doen:

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

Ik wil dit op het modelniveau doen, niet het formulierniveau. Ik zou in feite het formulierniveau kunnen vinden om een ​​ander bereik te hebben; B.v., gebruik percentages [0,100] op het formulierniveau, maar vertalen naar [0,1] in het model.

Is dit mogelijk, en zo ja, hoe zou ik het doen?


Antwoord 1, Autoriteit 100%

De antwoorden beschrijven tot nu toe hoe u formulieren kunt laten valideren. U kunt ook validators in het model plaatsen. Gebruik Minvaluevalidator en MAXVALUEVALIDATOR .

Bijvoorbeeld:

from django.core.validators import MaxValueValidator, MinValueValidator
...
weight = models.FloatField(
    validators=[MinValueValidator(0.0), MaxValueValidator(1.0)],
)

bewerken :

Dat voegt echter geen SQL-beperking toe.

U kunt SQL-beperkingen toevoegen zoals beschreven hier als CheckConstraints in Meta.constraints.

Gecombineerd voorbeeld:

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'),
            )

Antwoord 2, Autoriteit 15%

Als u een beperking op het formulierniveau nodig hebt, kunt u min_valueen max_valueNAAR Formaatveld :

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

Maar als u het moet verplaatsen naar modelniveau, moet u BASE models.FloatFieldCLASS

verlengen

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)

Dan kunt u het gebruiken in modellen

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

Antwoord 3

Het is redelijk wat tijd geweest en de Gemeenschap stemde antwoord is goed genoeg, gebaseerd op django ingebouwde ins, maar hier is een andere aanpak, probleemspecifiek, na de Documentatie van Django .

Maak een aangepaste validator

# 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},)

Gebruik je validator in je modellen

# app/models.py

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

U kunt de validator zelfs parametrisch maken om generieker te zijn.

BEWERKEN – BELANGRIJK

Houd er rekening mee dat een validator wordt aangeroepen tijdens de clean()-methode van het formulier.

I.E. als u rechtstreeks een object probeert te maken zonder een formulier te gebruiken, wordt uw validator NIETaangeroepen.

Er zijn mensen die het niet aanbevelen, maar als je validators wilt aanroepen terwijl je een object maakt, overschrijf dan de opslagmethode.

# 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])

Other episodes