经过大量的实验和对User
模型的最小影响,终于实现了它。[感谢 的不同想法]
############ 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.value
def custom_getattribute(self, name):
val = object.__getattribute__(self, name)
if name == "username":
val = iunicode(val)
return val
def 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_getattribute
User.save = MethodType(auth_user_save, None, User)
#####################################################
我测试了它,并按预期工作。:D
因此,这是 :
from django.test.testcases import TestCase
def 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 user
class 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()))
###################### 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 clone
from django.db.models.query import QuerySet
QuerySet._filter_or_exclude = _filter_or_exclude
#############################################################
这将允许User.objects.get(username='yugal')
并User.objects.get(username='YUGAl')
产生相同的用户。