Je crée un site Web pour mon projet et j'ai un champ appelé Purchase_Date:

class Member_Registration(models.Model):
    Purchase_Date=models.DateField(max_length=10, help_text="Enter the date of purchase")

Je veux lancer une erreur si l'utilisateur sélectionne une date qui est dans le futur. Comment dois-je procéder?

4
Tanmay 17 avril 2018 à 18:52

3 réponses

Meilleure réponse

Ce que vous voulez, c'est un validateur:

from datetime import date
from django.core.exceptions import ValidationError
from django.db import models

def no_future(value):
    today = date.today()
    if value > today:
        raise ValidationError('Purchase_Date cannot be in the future.')

class Member_Registration(models.Model):
    Purchase_Date=models.DateField(help_text="Enter the date of purchase", validators=[no_future])
2
Kal 17 avril 2018 à 15:58

Vous pouvez créer votre propre validateur pour cela.

from django.core.exceptions import ValidationError
from django.db import models
from django.utils import timezone as tz

def validate_date_not_in_future(value):
    if value > tz.now():
        raise ValidationError('date is in the future')

class MemberRegistration(models.Model):
    purchase_date = models.DateField(
        validators=[validate_date_not_in_future])
1
Ralf 17 avril 2018 à 15:57

Depuis Django 2.2, vous n'avez plus à créer de validateur personnalisé pour cette logique car le limit_value peut désormais être appelé.

from datetime import date

from django.core.validators import MaxValueValidator
from django.db import models
from django.utils.translation import gettext_lazy as _

class MemberRegistration(models.Model):
    purchase_date=models.DateField(
        help_text=_('Enter the date of purchase'),
        validators=[MaxValueValidator(limit_value=date.today)]
        verbose_name=_('purchase date')
    )

Notez que le limit_value est défini sur date.today (un appelable) et non sur date.today(). Si nous avons utilisé date.today(), chaque fois que le code est chargé pour la première fois, il utilisera cette date à partir de ce point jusqu'à ce que le code soit rechargé. L'utilisation de date.today (appelable) rend cette dynamique et elle récupérera la date du jour à chaque appel du validateur. L'erreur que vous recevrez maintenant sur le frontal sera désormais "Assurez-vous que cette valeur est inférieure ou égale à 2019-12-02" (remplacez 2019-12-02 par la date d'aujourd'hui si vous lisez ceci à l'avenir). Si vous souhaitez conserver votre message d'erreur plus spécifique au champ et avoir un message personnalisé, les exemples d'écriture de votre propre validateur seraient nécessaires.

Pour ce que cela vaut, si vous êtes très préoccupé par l'intégrité des données, vous pouvez ajouter une CheckConstraint sur ce champ pour empêcher la base de données d'autoriser également les dates futures. Cela garantirait que si la validation est ignorée pour une raison quelconque, la valeur ne peut pas être supérieure à ce que vous attendez:

from datetime import date

from django.core.validators import MaxValueValidator
from django.db import models
from django.db.models.functions import Now
from django.utils.translation import gettext_lazy as _

class MemberRegistration(models.Model):
    purchase_date=models.DateField(
        help_text=_('Enter the date of purchase'),
        validators=[MaxValueValidator(limit_value=date.today)]
        verbose_name=_('purchase date')
    )

    class Meta:
        constraints = [
            models.CheckConstraint(
                check=models.Q(purchase_date__lte=Now()),
                code='purchase_date_cannot_be_future_dated'
            )
        ]

Si nous essayions de faire MemberRegistration(purchase_date=date(2099, 1, 1)).save() nous obtiendrions l'erreur:

django.db.utils.IntegrityError: une nouvelle ligne pour la relation "app_label_memberregistration" viole la contrainte de vérification "Purchase_date_cannot_be_future_dated" DÉTAIL: La ligne défaillante contient (2099-01-01).

2
Michael B 2 déc. 2019 à 17:01