views:

1022

answers:

3

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.

A: 

"User" may be a bad name for a model with such specialized functionality. Try using another name and see whether it works or not.

Johannes
Well I am sure the name is not a problem here.
Baishampayan Ghose
+3  A: 

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.

S.Lott
Well, I am well aware of custom auth backends but I don't need this for (only) auth, but for other things, like usernames used in URLs, etc.
Baishampayan Ghose
+2  A: 

Managers can't be added to classes with simple attribute assignment (User.objects = MyManager()). Look at the ModelBase metaclass (db/models/base.py) to see what all is done for you behind the scenes when you subclass Model.

You should be able to make it work with User.add_to_class('objects', MyManager()). Alternatively, you could make a proxy subclass of User and add the manager there.

Carl Meyer
Thanks for the tip. I will try it out.
Baishampayan Ghose