pythondjango

Issue with Django CheckConstraint


I'm trying to add some new fields to an existing model and also a constraint related to those new fields:

class User(models.Model):
    username = models.CharField(max_length=32)

    # New fields ##################################
    has_garden = models.BooleanField(default=False)
    garden_description = models.CharField(
        max_length=32,
        null=True,
        blank=True,
    )

    class Meta:
        constraints = [
            models.CheckConstraint(
                check=Q(has_garden=models.Value(True))
                & Q(garden_description__isnull=True),
                name="garden_description_if_has_garden",
            )
        ]

The problem is that when I run my migrations I get the following error:

django.db.utils.IntegrityError: check constraint "garden_description_if_has_garden" is violated by some row

But I don't understand how the constraint is being violated if no User has a has_garden, the field is just being created and also its default value is False 🤔.

I'm using django 3.2 with postgresql.

What is the proper way to add this constraint? If it's of any use here's the autogenerated migration:

# Generated by Django 3.2.25 on 2025-01-15 23:52

import django.db.models.expressions
from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ("some_app", "0066_user"),
    ]

    operations = [
        migrations.AddField(
            model_name="user",
            name="garden_description",
            field=models.CharField(blank=True, max_length=32, null=True),
        ),
        migrations.AddField(
            model_name="user",
            name="has_garden",
            field=models.BooleanField(default=False),
        ),
        migrations.AddConstraint(
            model_name="user",
            constraint=models.CheckConstraint(
                check=models.Q(
                    ("has_garden", django.db.models.expressions.Value(True)),
                    ("garden_description__isnull", True),
                ),
                name="garden_description_if_has_garden",
            ),
        ),
    ]

Solution

  • Far as I can see your constraint is trying to make sure that all instances of user have has_garden=True, which would cause a violation if a user has has_garden=False.

    Here we add a constraint to either check if has_garden is true and garden_description is not null, or if has_garden is false and garden_descriptionn is null

    class User(models.Model):
        username = models.CharField(max_length=32)
    
        # New fields ##################################
        has_garden = models.BooleanField(default=False)
        garden_description = models.CharField(
            max_length=32,
            null=True,
            blank=True,
        )
    
        class Meta:
            constraints = [
                models.CheckConstraint(
                    check=(
                        Q(has_garden=models.Value(True))
                        & Q(garden_description__isnull=False)
                        | (
                            Q(has_garden=models.Value(False))
                            & Q(garden_description__isnull=True)
                        )
                    ),
                    name="garden_description_if_has_garden",
                )
            ]