Unique model field in Django and case sensitivity (postgres) Unique model field in Django and case sensitivity (postgres) postgresql postgresql

Unique model field in Django and case sensitivity (postgres)


You could define a custom model field derived from models.CharField.This field could check for duplicate values, ignoring the case.

Custom fields documentation is here http://docs.djangoproject.com/en/dev/howto/custom-model-fields/

Look at http://code.djangoproject.com/browser/django/trunk/django/db/models/fields/files.py for an example of how to create a custom field by subclassing an existing field.

You could use the citext module of PostgreSQL https://www.postgresql.org/docs/current/static/citext.html

If you use this module, the the custom field could define "db_type" as CITEXT for PostgreSQL databases.

This would lead to case insensitive comparison for unique values in the custom field.


Alternatively you can change the default Query Set Manager to do case insensitive look-ups on the field. In trying to solve a similar problem I came across:

http://djangosnippets.org/snippets/305/

Code pasted here for convenience:

from django.db.models import Managerfrom django.db.models.query import QuerySetclass CaseInsensitiveQuerySet(QuerySet):    def _filter_or_exclude(self, mapper, *args, **kwargs):        # 'name' is a field in your Model whose lookups you want case-insensitive by default        if 'name' in kwargs:            kwargs['name__iexact'] = kwargs['name']            del kwargs['name']        return super(CaseInsensitiveQuerySet, self)._filter_or_exclude(mapper, *args, **kwargs)# custom manager that overrides the initial query setclass TagManager(Manager):    def get_query_set(self):        return CaseInsensitiveQuerySet(self.model)# and the model itselfclass Tag(models.Model):    name = models.CharField(maxlength=50, unique=True, db_index=True)    objects = TagManager()    def __str__(self):        return self.name


Explicit steps for Mayuresh's answer:

  1. in postgres do: CREATE EXTENSION citext;

  2. in your models.py add:

    from django.db.models import fieldsclass CaseInsensitiveTextField(fields.TextField):    def db_type(self, connection):        return "citext"

    reference: https://github.com/zacharyvoase/django-postgres/blob/master/django_postgres/citext.py

  3. in your model use: name = CaseInsensitiveTextField(unique=True)