Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: Perform case-insensitive lookups by default

I need to perform case-insensitive queries on username by default when using the Django Auth framework.

I tried fixing the issue by writing a custom subclass of Queryset and overriding the _filter_or_exclude method and then using that subclass in a custom manager for the User model-

from django.db.models import Manager
from django.db.models.query import QuerySet
from django.contrib.auth.models import UserManager

class MyQuerySet(QuerySet):
    def _filter_or_exclude(self, negate, *args, **kwargs):
        if 'username' in kwargs:
            kwargs['username__iexact'] = kwargs['username']
            del kwargs['username']
        return super(MyQuerySet, self)._filter_or_exclude(negate, *args, **kwargs)

class MyUserManager(UserManager):
    def get_query_set(self):
        return MyQuerySet(self.model)

User.objects = MyUserManager()

But this approach didn't work and I am getting an weird error when I try doing User.objects.get(username='Foo').

Any help would be appreciated.

Update: I am including the exact error that I am getting.

/usr/lib/python2.5/site-packages/django/db/models/query.py in get(self, *args, **kwargs)
    295         keyword arguments.
    296         """
--> 297         clone = self.filter(*args, **kwargs)
    298         num = len(clone)
    299         if num == 1:

/usr/lib/python2.5/site-packages/django/db/models/query.py in filter(self, *args, **kwargs)
    481         set.
    482         """
--> 483         return self._filter_or_exclude(False, *args, **kwargs)
    484 
    485     def exclude(self, *args, **kwargs):

/home/ghoseb/src/git/ocricket.git/ocricket/user/models.py in _filter_or_exclude(self, negate, *args, **kwargs)
     38             kwargs['username__iexact'] = kwargs['username']
     39             del kwargs['username']
---> 40         return super(MyQuerySet, self)._filter_or_exclude(negate, *args, **kwargs)
     41 
     42 class MyUserManager(UserManager):

/usr/lib/python2.5/site-packages/django/db/models/query.py in _filter_or_exclude(self, negate, *args, **kwargs)
    499             clone.query.add_q(~Q(*args, **kwargs))
    500         else:
--> 501             clone.query.add_q(Q(*args, **kwargs))
    502         return clone
    503 

/usr/lib/python2.5/django/db/models/sql/query.py in add_q(self, q_object, used_aliases)

/usr/lib/python2.5/django/db/models/sql/query.py in add_filter(self, filter_expr, connector, negate, trim, can_reuse, process_extras)

/usr/lib/python2.5/django/db/models/sql/query.py in get_meta(self)

<type 'exceptions.AttributeError'>: 'NoneType' object has no attribute '_meta'

Update: By the way, I just wanted to mention that when I copy the logic inside my _filter_or_exclude method into the actual QuerySet class, it works flawlessly.

like image 803
Baishampayan Ghose Avatar asked Feb 10 '09 11:02

Baishampayan Ghose


1 Answers

You don't want to mess with internal features of Django classes. That way lies trouble with every upgrade in the future.

If you want to change the way people authenticate, write a custom authentication backend.

Here are two recipes.

http://www.davidcramer.net/code/224/logging-in-with-email-addresses-in-django.html

http://www.djangosnippets.org/snippets/577/

Both of these us email instead of username. It's not hard to use case-insensitive query instead of an email query.

like image 198
S.Lott Avatar answered Oct 13 '22 09:10

S.Lott