Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why should I set max_length when using Choices in a Django model?

In the official Django 2 tutorial I found this:

from django.db import models

class Student(models.Model):
    FRESHMAN = 'FR'
    SOPHOMORE = 'SO'
    JUNIOR = 'JR'
    SENIOR = 'SR'
    YEAR_IN_SCHOOL_CHOICES = (
        (FRESHMAN, 'Freshman'),
        (SOPHOMORE, 'Sophomore'),
        (JUNIOR, 'Junior'),
        (SENIOR, 'Senior'),
    )
    year_in_school = models.CharField(
        max_length=2,
        choices=YEAR_IN_SCHOOL_CHOICES,
        default=FRESHMAN,
    )

Now my question is does using choices mean that only either of the four defined values is valid for this field? If so what is the use of specifying the max_length? If not, why not use a validator that validates if the value is actually exacly one of the specified ones or at least a validator that only accepts an specific length not just an upper bound.

like image 426
ladybug Avatar asked May 25 '18 13:05

ladybug


2 Answers

The max_length is enforced at the database level, but the choices are enforced at python code level (when calling full_clean() or clean_<fieldname>()).

They are independent of each other.

If you set a value to your field other than the specified choices and you don't call instance.full_clean() or instance.clean_<fieldname>(), it could still get saved to the database without raising errors.

But if you use djangos forms, the choices validation is done for you (the form calls full_clean()) and you don't need to worry about it.


This means, for example, if you set max_length smaller than your largest option in choices, your database will silently truncate the values for that field or raise a DatabaseError; either way you will not get it to work.

This separation is useful, for example, if you want to add more choices later; if the new options are not larger than max_length, there will be no need to to change the database structure (that means, the new migration will NOT issue alter table SQL statements).

like image 143
Ralf Avatar answered Nov 08 '22 00:11

Ralf


I ran into this issue recently, except that I wasn't just using a two letter code so it was a bit tedious to make sure I had a valid max_length. I ended up doing something like this:

year_in_school = models.CharField(
    max_length=max(len(v[0]) for v in YEAR_IN_SCHOOL_CHOICES),
    choices=YEAR_IN_SCHOOL_CHOICES,
    default=FRESHMAN,
)

If I ever add an option that exceeds the existing max length, makemigrations will detect that and add that change to the migration.

like image 32
Vinay Pai Avatar answered Nov 08 '22 00:11

Vinay Pai