Django : Case insensitive matching of username from auth user? Django : Case insensitive matching of username from auth user? python python

Django : Case insensitive matching of username from auth user?


As of Django 1.5, making usernames case insensitive is straightforward:

class MyUserManager(BaseUserManager):    def get_by_natural_key(self, username):        return self.get(username__iexact=username)

Sources: 1, 2


I modified few lines in my registration and login process that seems to work for me. With my solution usernames will still be displayed like the user wrote them when registering, but it will not allow others to use the same username written differently. It also allows users to login without worrying about writing the case sensitive username.

I modified the registration form to search for case insensitive usernames.

This is line from my validation of username, it searches for user with this username.

User._default_manager.get(username__iexact=username)

Then I needed to allow users to login with case insensitive usernames.

From my login view:

username = request.POST['username']password = request.POST['password']caseSensitiveUsername = usernametry:  findUser = User._default_manager.get(username__iexact=username)except User.DoesNotExist:  findUser = Noneif findUser is not None:  caseSensitiveUsername = findUser.get_usernameuser = auth.authenticate(username=caseSensitiveUsername, password=password)


Finally got it :

With so much experimenting and minimum effect on User model, finally achieved it.[ Thanks to Mr. @freakish for a different thought ]

Here it is :

############ username case-insensitivity ############class iunicode(unicode):    def __init__(self, value):        super(iunicode, self).__init__(value)        self.value = value    def __eq__(self, other):        if isinstance(other, str) or isinstance(other, unicode):            return self.value.lower() == other.lower()        if isinstance(other, self.__class__):            return other == self.valuedef custom_getattribute(self, name):    val = object.__getattribute__(self, name)    if name == "username":        val = iunicode(val)    return valdef auth_user_save(self, *args, **kwargs): # Ensures lowercase usernames    username = self.username    if username and type(username) in [unicode, str, iunicode]:        self.username = username.lower()   # Only lower case allowed    super(User, self).save(*args, **kwargs)User.__getattribute__ = custom_getattributeUser.save = MethodType(auth_user_save, None, User)#####################################################

I tested it and it worked as expected. :D

So, here are the testcases :

from django.test.testcases import TestCasedef create_user(data='testuser'):    email = '%s@%s.com' % (data, data)    user = G(User, username=data, email=email, is_active=True)    user.set_password(data)    user.save()    return userclass UsernameCaseInsensitiveTests(TestCase):    def test_user_create(self):        testuser = 'testuser'        user = create_user(testuser)        # Lowercase        self.assertEqual(testuser, user.username)        # Uppercase        user.username = testuser.upper()        user.save()        self.assertEqual(testuser, user.username)def test_username_eq(self):    testuser = 'testuser'    user = create_user(testuser)    self.assertTrue(isinstance(user.username, iunicode))    self.assertEqual(user.username, testuser)    self.assertEqual(user.username, testuser.upper())    self.assertTrue(user.username == testuser.upper())    self.assertTrue(testuser.upper() == user.username)    self.assertTrue(user.username == iunicode(testuser.upper()))
Implicit Case-insensitive queries for database
###################### QuerySet #############################def _filter_or_exclude(self, negate, *args, **kwargs):    if 'username' in kwargs:        kwargs['username__iexact'] = kwargs['username']        del kwargs['username']    if args or kwargs:        assert self.query.can_filter(),\        "Cannot filter a query once a slice has been taken."    from django.db.models import Q    clone = self._clone()    if negate:        clone.query.add_q(~Q(*args, **kwargs))    else:        clone.query.add_q(Q(*args, **kwargs))    return clonefrom django.db.models.query import QuerySetQuerySet._filter_or_exclude = _filter_or_exclude#############################################################

This will allow, User.objects.get(username='yugal') & User.objects.get(username='YUGAl') yield the same user.