32๐
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.
8๐
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 Manager
from django.db.models.query import QuerySet
class 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 set
class TagManager(Manager):
def get_query_set(self):
return CaseInsensitiveQuerySet(self.model)
# and the model itself
class Tag(models.Model):
name = models.CharField(maxlength=50, unique=True, db_index=True)
objects = TagManager()
def __str__(self):
return self.name
- [Django]-Caching query results in django
- [Django]-Django: no such table: django_session
- [Django]-When saving, how can you check if a field has changed?
7๐
a very simple solution:
class State(models.Model):
name = models.CharField(max_length=50, unique=True)
def clean(self):
self.name = self.name.capitalize()
- [Django]-SQLAlchemy Model Django like Save Method?
- [Django]-Django โ getlist()
- [Django]-"Disabled" option for choiceField โ Django
7๐
Explicit steps for Mayureshโs answer:
-
in postgres do: CREATE EXTENSION citext;
-
in your models.py add:
from django.db.models import fields class CaseInsensitiveTextField(fields.TextField): def db_type(self, connection): return "citext"
reference: https://github.com/zacharyvoase/django-postgres/blob/master/django_postgres/citext.py
-
in your model use: name = CaseInsensitiveTextField(unique=True)
- [Django]-Django view โ load template from calling app's dir first
- [Django]-In a Django QuerySet, how to filter for "not exists" in a many-to-one relationship
- [Django]-Execute code in Django after response has been sent to the client
6๐
On the Postgres side of things, a functional unique index will let you enforce unique values without case. citext is also noted, but this will work with older versions of PostgreSQL and is a useful technique in general.
Example:
# create table foo(bar text);
CREATE TABLE
# create unique index foo_bar on foo(lower(bar));
CREATE INDEX
# insert into foo values ('Texas');
INSERT 0 1
# insert into foo values ('texas');
ERROR: duplicate key value violates unique constraint "foo_bar"
- [Django]-In django do models have a default timestamp field?
- [Django]-Determine complete Django url configuration
- [Django]-Django, template context processors
5๐
Besides already mentioned option to override save, you can simply store all text in lower case in database and capitalize them on displaying.
class State(models.Model):
name = models.CharField(max_length=50, unique=True)
def save(self, force_insert=False, force_update=False):
self.name = self.name.lower()
super(State, self).save(force_insert, force_update)
- [Django]-Django populate() isn't reentrant
- [Django]-Django REST Framework โ Serializing optional fields
- [Django]-Do properties work on Django model fields?
3๐
You can use lookup=โiexactโ in UniqueValidator on serializer, like this:
class StateSerializer(serializers.ModelSerializer):
name = serializers.CharField(validators=[
UniqueValidator(
queryset=models.State.objects.all(),lookup='iexact'
)]
django version: 1.11.6
- [Django]-Access-Control-Allow-Origin in Django app
- [Django]-Why middleware mixin declared in django.utils.deprecation.py
- [Django]-Django-Rest-Framework 3.0 Field name '<field>' is not valid for model `ModelBase`
2๐
If you donโt want to use a postgres-specific solution, you can create a unique index on the field with upper()
to enforce uniqueness at the database level, then create a custom Field
mixin that overrides get_lookup()
to convert case-sensitive lookups to their case-insensitive versions. The mixin looks like this:
class CaseInsensitiveFieldMixin:
"""
Field mixin that uses case-insensitive lookup alternatives if they exist.
"""
LOOKUP_CONVERSIONS = {
'exact': 'iexact',
'contains': 'icontains',
'startswith': 'istartswith',
'endswith': 'iendswith',
'regex': 'iregex',
}
def get_lookup(self, lookup_name):
converted = self.LOOKUP_CONVERSIONS.get(lookup_name, lookup_name)
return super().get_lookup(converted)
And you use it like this:
from django.db import models
class CICharField(CaseInsensitiveFieldMixin, models.CharField):
pass
class CIEmailField(CaseInsensitiveFieldMixin, models.EmailField):
pass
class TestModel(models.Model):
name = CICharField(unique=True, max_length=20)
email = CIEmailField(unique=True)
You can read more about this approach here.
- [Django]-Django REST Framework: raise error when extra fields are present on POST
- [Django]-How does Django's nested Meta class work?
- [Django]-How to monkey patch Django?
1๐
You can do this by overwriting the Modelโs save method โ see the docs. Youโd basically do something like:
class State(models.Model):
name = models.CharField(max_length=50, unique=True)
def save(self, force_insert=False, force_update=False):
if State.objects.get(name__iexact = self.name):
return
else:
super(State, self).save(force_insert, force_update)
Also, I may be wrong about this, but the upcoming model-validation SoC branch will allow us to do this more easily.
- [Django]-How to use custom AdminSite class?
- [Django]-What's the difference between Model.id and Model.pk in django?
- [Django]-How can I obtain the model's name or the content type of a Django object?
0๐
Solution from suhail worked for me without the need to enable citext, pretty easy solution only a clean function and instead of capitalize I used upper()
. Mayureshโs solution also works but changed the field from CharField
to TextField
.
class State(models.Model):
name = models.CharField(max_length=50, unique=True)
def clean(self):
self.name = self.name.upper()
- [Django]-Django Generic Views using decorator login_required
- [Django]-How to use curl with Django, csrf tokens and POST requests
- [Django]-Update all models at once in Django