Hey !
I’m writing a custom model field and would like it to come with a database CHECK constraint. The actual use case is DB validation of Django’s choices
, to avoid invalid values (since the data can be edited from outside of Django).
I thought that could be done with contribute_to_class
, and indeed it’s almost possible.
Here’s what I got so far:
class ChoiceField(models.CharField):
def contribute_to_class(self, cls, name, private_only=False):
super().contribute_to_class(cls, name, private_only)
accepted_values = [c[0] for c in self.choices]
cls._meta.constraints.append(
models.CheckConstraint(
check=models.Q(**{f"{name}__in": accepted_values}),
name=f"%(app_label)s_%(class)s_{name}_valid_choices"
)
)
It works exactly as I’d like when I specify an empty constraints list in my model’s Meta (meaning makemigrations will create the constraints).
But for some reason, if I don’t specify an empty list, or if my model has no Meta at all, the constraints aren’t picked up (makemigrations doesn’t create the constraints).
I stumbled about this ticket, which seems very similar, and where it was suggested to ask here (in that case, it was about “indexes”, and strangely they seem to have the exact opposite issue, where it works as expected without Meta, but the index is added twice with the Meta).
Does anyone understand what could be the cause of the issue ?
Wouldn’t it be nice for Django to support this ? DB data validation is really a must when you can’t rely on python validation (migrating large amount of data, DB operated by other clients, etc…)
Cheers !!
Olivier