From the constraints reference in the django documentation,
Validation of Constraints
In general constraints are not checked during full_clean(), and do not raise ValidationErrors. Rather you’ll get a database integrity error on save(). UniqueConstraints without a condition (i.e. non-partial unique constraints) are different in this regard, in that they leverage the existing validate_unique() logic, and thus enable two-stage validation. In addition to IntegrityError on save(), ValidationError is also raised during model validation when the UniqueConstraint is violated.
dj-check-constraint-validation.CheckConstraintMixin
will programmatically generate form validation from the Q objects
specified in the CheckConstraint.check. This leads
us to define the check constraint on the model once without having to define similar logic again on the form.
pip install dj-check-constraint-validation
from django.db import models
from django import forms
from django.db.models import CheckConstraint, F, Q
from dj_check_constraint_validation import CheckConstraintsMixin
class Dog(models.Model):
name = models.CharField(max_length=32)
nick_name = models.CharField(max_length=32)
class Meta:
constraints = [
CheckConstraint(check=~Q(name=F("nick_name")), name="name-nick-name-check"),
]
class DogForm(CheckConstraintsMixin, forms.ModelForm):
class Meta:
model = Dog
fields = ["name", "nick_name"]
The code to evaluate Q objects in python is in the eval_q
function. This function currently supports the following:
type | example |
---|---|
Q | CheckConstraint(check=~Q(name="Bad name"), ...) |
Q with F | CheckConstraint(check=~Q(name=F("nick_name")), ...) |
Q with CombinedExpression | CheckConstraint(check=~Q(balance=F("price") - F("discount"), ...) |
There is no support for field lookups