问题
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.
回答1:
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.
回答2:
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.
回答3:
Here's a recipe for the auth use case: Django : Case insensitive matching of username from auth user? You're probably best off using separate solutions for each of your use cases.
来源:https://stackoverflow.com/questions/531892/django-perform-case-insensitive-lookups-by-default