Yug*_*dle 13 python django operator-overloading
Django默认情况下将用户名视为区分大小写,现在用于身份验证我已经编写了自己的Authentication Backend用户名,以便在身份验证时处理不区分大小写的用户名.
如下所示:http://blog.shopfiber.com/?p = 220
现在,问题是:
我有各种各样的观点和实用方法,可以比较username一些刺痛.
即
request.user.username == username_from_some_other_system_as_str
Run Code Online (Sandbox Code Playgroud)
现在,如果用户名是yugal:
request.user.username == 'Yugal' # Returns False
Run Code Online (Sandbox Code Playgroud)
现在,它应该返回True[我想要实现的目标]
为此,我记得C++几天Operator Overloading.但我不认为简单地为django做那个auth user将是一个好主意,因为它auth user是紧密结合的django.此外,重载==将使整个类不仅对username字段不区分大小写.
那么,username即使在整个过程中进行比较,我应该如何处理这种不区分大小写的问题.
注意:
get_username始终无法创建返回小写用户名的方法,因为它需要重新考虑所有代码才能使用它.您可以为您的代码执行一次,但如果您使用的是第三方django应用程序则无法实现.
我知道这user.username.lower() = something.lower()是可能的,但是容易出错,而不是针对多开发人员设置中经常使用的东西的写入解决方案.
我SomeModel.objects.filter(username__iexact=username)尽可能地使用过.但这仍然让系统容易受到任何不知情的开发人员的错误的影响.
======================================
从概念上找出解决方案,但无法使其工作(帮助):
####### Custom CharField for username case-insensitivity #######
from django.db.models.fields import CharField
class iUnicode:
def __init__(self, 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 __unicode__(self):
return unicode(self.value)
def __str__(self):
return self.__unicode__()
class UsernameCharField(CharField):
def to_python(self, value): # Its not getting called
unicode_val = super(CharField, self).to_python(value)
return iUnicode(unicode_val)
if User._meta.local_fields[1].name == 'username':
User._meta.local_fields[1] = UsernameCharField(max_length=30)
User._meta.local_fields[1].model = User
################################################################
Run Code Online (Sandbox Code Playgroud)
我假设to_python用于将从数据库接收的值转换为unicodepython.但是,我猜我to_python没有被召唤.
这还将确保第三方应用程序中的大小写不敏感,并且不需要任何重新分解.它将修补
User其核心.我将在__init__.py第一次添加此内容INSTALLED_APP
我究竟做错了什么 ?
Jos*_*ley 26
从Django 1.5开始,使用户名不敏感是很简单的:
class MyUserManager(BaseUserManager):
def get_by_natural_key(self, username):
return self.get(username__iexact=username)
Run Code Online (Sandbox Code Playgroud)
我在注册和登录过程中修改了几行似乎对我有用.使用我的解决方案,用户名仍将显示为用户在注册时编写的用户名,但不允许其他人使用不同的用户名.它还允许用户登录而无需担心编写区分大小写的用户名.
我修改了注册表单以搜索不区分大小写的用户名.
这是我对用户名的验证,它使用此用户名搜索用户.
User._default_manager.get(username__iexact=username)
Run Code Online (Sandbox Code Playgroud)
然后我需要允许用户使用不区分大小写的用户名登录.
从我的登录视图:
username = request.POST['username']
password = request.POST['password']
caseSensitiveUsername = username
try:
findUser = User._default_manager.get(username__iexact=username)
except User.DoesNotExist:
findUser = None
if findUser is not None:
caseSensitiveUsername = findUser.get_username
user = auth.authenticate(username=caseSensitiveUsername, password=password)
Run Code Online (Sandbox Code Playgroud)
终于明白了:
经过如此多的实验和对User模型的最小影响,终于实现了。[感谢@freakish先生的不同想法]
这里是 :
############ 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)
#####################################################
Run Code Online (Sandbox Code Playgroud)
我测试了它,它按预期工作。: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()))
Run Code Online (Sandbox Code Playgroud)
对数据库的隐式不区分大小写的查询
###################### 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
#############################################################
Run Code Online (Sandbox Code Playgroud)
这将允许User.objects.get(username='yugal')并User.objects.get(username='YUGAl')产生相同的用户。
| 归档时间: |
|
| 查看次数: |
10823 次 |
| 最近记录: |