With my current code I know it is not working, I can still save duplicate values in a model that uses my custom field. So I’m wondering if what I want to do is impossible, or if parts of it are impossible (like automatically assigning the model and app name in the name of the new UniqueConstraint).
I know I could make a custom field that automatically converts everything to lowercase before saving, but then that does not help me preserve the casing of, for example, a name such as Charles de Gaulle, so it’s not a solution.
If it is not impossible, what am I doing wrong?
# fields.py
from django.db import models
from django.db.models import UniqueConstraint
from django.db.models.functions import Lower
class CIUniqueChar255Field(models.CharField):
def __init__(self, *args, **kwargs):
kwargs['max_length'] = kwargs.get('max_length', 255)
kwargs['unique'] = kwargs.get('unique', True)
super().__init__(*args, **kwargs)
def contribute_to_class(self, cls, name, **kwargs):
super().contribute_to_class(cls, name, **kwargs)
if not cls._meta.abstract:
meta = getattr(cls, 'Meta', None)
if not hasattr(meta, 'constraints'):
setattr(cls, 'Meta', type('Meta', (), {'constraints': []}))
meta = cls.Meta
self.model = cls
app_name = self.model._meta.app_label
model_name = self.model._meta.model_name
meta.constraints.append(
UniqueConstraint(
Lower([name]),
name=f'ci_unique_{name}_{model_name}_{app_name}'
)
)
# models.py
from .fields import CIUniqueChar255Field
class MyModel(models.Model):
identifier = CIUniqueChar255Field()