simple CheckConstraint syntax?

I am new to Django and trying to define what should be a simple database CheckConstraint. The intention is to prevent two boolean values, “light” and “pigment”, from both being True. Either one or the other or neither can be True as a valid case. Simple logic, but I can’t seem get the syntax correct. Can someone please show me how to correctly specify this CheckConstraint?

Here is the model:

from django.db import models
from django.contrib.auth.models import User
from django.contrib.auth import authenticate

class Colors(models.Model):
name = models.CharField(max_length=200, unique=True)
light = models.BooleanField(default = False)
pigment = models.BooleanField(default = False)
owner = models.ForeignKey(User, on_delete=models.PROTECT,
blank = True, null = True)
note = models.TextField(blank = True)

def __str__(self):
    return self.name

# this below fails with:
# NameError: name 'light' is not defined
class Meta:
    constraints = [
        models.CheckConstraint(
            check = not (models.Q(light == True) and models.Q(pigment == True)),
            name = "light and pigment"
            )
    ]

Your conditions in the constraint aren’t python expressions, they’re positional parameters being passed in to the Q object initializer. (Take a look at Complex Lookups with Q objects.)
Try:
~(models.Q(light=True) & models.Q(pigment=True))
or:
models.Q(light__ne=True) | models.Q(pigment__ne=True)

Yes. This is the error:

NameError: name ‘light’ is not defined

Sorry - hit save too soon - see reply above your response at simple CheckConstraint syntax?.

<opinion>
I believe the code looks better if you import the individual components (such as Q) rather than just importing the module.
For example, your code would become:

from django.db.models import (Model, CharField, BoooleanField, ForeignKey, 
    TextField, Q, CheckConstraint)
from django.contrib.auth.models import User
from django.contrib.auth import authenticate

class Colors(models.Model):
  name = CharField(max_length=200, unique=True)
  light = BooleanField(default = False)
  pigment = BooleanField(default = False)
  owner = ForeignKey(User, on_delete=models.PROTECT,
                blank = True, null = True)
  note = TextField(blank = True)

  def __str__(self):
    return self.name

  # this below fails with:
  # NameError: name 'light' is not defined
  class Meta:
    constraints = [
        CheckConstraint(
            check = ~ (Q(light=True) & Q(pigment=True)),
            name = "light and pigment"
            )
    ]

which I think is far easier to read overall. (That’s assuming I haven’t done something on the fly here to really butcher the syntax beyond recognition.)
</opinion>

1 Like

Ken,

Thank you so much. This worked perfectly.

I have been pouring over the documentation and had not found the article you pointed out. Thank you again.

Ken

1 Like