djangoenumscheck-constraints

Check Constraint in Django


I want to include a check constraint for my model in my members app where the sex field should be male, female or null. Here is my code:

from django.db import models
from django.db.models import CheckConstraint, Q

# Create your models here.
class Member(models.Model):
    firstname = models.CharField(max_length=255)
    lastname = models.CharField(max_length=255)
    telephonenum = models.IntegerField(null=True)
    sex = models.CharField(max_length=10, null=True)
    CheckConstraint(check=Q((sex == "Female") | (sex == "Male")), name="check_sex")

This code is not working I can still make sex field something different than Female or Male.

I've tried this code but it didn't work either:

from django.db import models

# Create your models here.
human_sex = (
    ("1", "Woman"),
    ("2", "Man"),
)

class Member(models.Model):

    firstname = models.CharField(max_length=255)
    lastname = models.CharField(max_length=255)
    telephonenum = models.IntegerField(null=True)
    sex = models.CharField(max_length=10, choices=human_sex, null=True)

Solution

  • You list the constraint in a list named constraints in the Meta of the model. You also used the Q object wrong, it should be used as a parameter name, like:

    class Member(models.Model):
        firstname = models.CharField(max_length=255)
        lastname = models.CharField(max_length=255)
        telephonenum = models.IntegerField(null=True)
        sex = models.CharField(max_length=10, null=True)
    
        class Meta:
            constraints = [
                CheckConstraint(
                    check=Q(sex='Female') | Q(sex='Male'), name='check_sex'
                )
            ]

    Django by default does not enforce the choices at the database level, so only ModelForms and serializer will check this. Without the aim to do a lot of self-promotion, I made a small package that can enforce fields with choices at the database level named django-enforced-choices [GitHub]. After installing the package, you can add a mixin to your model with:

    from django.db import models
    from django_enforced_choices.models import ChoicesConstraintModelMixin
    
    # Create your models here.
    human_sex = (
        ('1', 'Woman'),
        ('2', 'Man'),
    )
    
    
    class Member(ChoicesConstraintModelMixin, models.Model):
    
        firstname = models.CharField(max_length=255)
        lastname = models.CharField(max_length=255)
        telephonenum = models.IntegerField(null=True)
        sex = models.CharField(max_length=10, choices=human_sex, null=True)

    This will then automatically add the constraint we added explicitly in the first code fragment.