Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django year validation returns "Ensure this value is less than or equal to 2016" in year 2017

Tags:

python

django

In my database, I have a record where the year field is 2016 but I need to change it to 2017. When I use Django admin to change it 2017, I get "Ensure this value is less than or equal to 2016.". What is wrong w/ my model?

class Track (models.Model):    
    artist = models.ForeignKey(Artist, blank=True, null=True, on_delete=models.SET_NULL, verbose_name="Artist")
    title = models.CharField(max_length=100, verbose_name="Title")
    year = models.PositiveSmallIntegerField(null=True, blank=True, validators=[MinValueValidator(1900), MaxValueValidator(datetime.datetime.now().year)], verbose_name="Year")
    timestamp = models.DateTimeField(default=timezone.now)
like image 598
bayman Avatar asked Jan 02 '17 06:01

bayman


1 Answers

This is a classic problem with django models/forms etc! The datetime.datetime.now().year code inside the validator is executed only once, when the source file is read for the first time. It is not executed every time the form is submitted! So it had the value 2016 when it was first executed and still has the same value now.

To quickly see my point, restart your application server - it should be ok then (the model will be re-evaluated and will get 2017 as datetime.date.today().year!). Of course, to really fix the issue, you must change your validation logic to use a custom validator (MaxValueValidator cannot be used) that will run everytime your form is submitted.

For example:

def my_year_validator(value):
    if value < 1900 or value > datetime.datetime.now().year:
        raise ValidationError(
            _('%(value)s is not a correcrt year!'),
            params={'value': value},
        )

...
# And then in your model:
year = models.PositiveSmallIntegerField(
    null=True, 
    blank=True, 
    validators=[my_year_validator], 
    verbose_name="Year"
)
like image 181
Serafeim Avatar answered Oct 03 '22 16:10

Serafeim