django1.10+python2.7
django admin 后台实现email登录,
1、重写一个验证后端,继承自系统的ModelBackend类,文档说重写 get_user()和
authenticate()方法,我这里只重写了authenticate()方法。然后利用Q对象同时查询username和email。
#cus_backends.py
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
from django.db.models import Q
class CusModelBackend(ModelBackend):
"""
Authenticates against settings.AUTH_USER_MODEL.
"""
def authenticate(self, username=None, password=None, **kwargs):
UserModel = get_user_model()
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
try:
user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username))
except Exception:
LOG.exception('login error:%s' % username)
# Run the default password hasher once to reduce the timing
# difference between an existing and a non-existing user (#20760).
UserModel().set_password(password)
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
2、settings文件里设置我们重写的后端验证类,类的路径只要在python的导包路径中就行
AUTHENTICATION_BACKENDS = ['cus_admin.cus_backends.CusModelBackend']
其实这样就已经完成了,可以邮箱登录了
但是还有些地方需要改进,django 的User模型类的email字段默认是可以重复的,但是如果要用email登录的话就应该让这个字段唯一。
文档说可以通过重写User模型类来实现,如果是新建工程,比较容易。如果是已经上线的工程比较麻烦,需要备份数据之类的。
我这里换了一种方法实现。就是重写UserAdmin和对应的form。查看源码可知UserAdmin的默认form是UserChangeForm,所以继承这个表单重写一个新的,增加验证email唯一性的方法。email可以为空,所以email存在时才会验证是否有重复email地址。注意用exclude排除自身,不然没法编辑已经存在的用户
from django import forms
from django.contrib import admin
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserChangeForm
class CusUserChangeForm(UserChangeForm):
def clean_email(self):
email = self.cleaned_data['email']
#注意用exclude排除自身
if email and User.objects.filter(email=email).exclude(pk=self.instance.pk).exists() :
raise forms.ValidationError("This email already used")
return email
class CusUserAdmin(UserAdmin):
#指定自定义的form
form = CusUserChangeForm
list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff','date_joined')
ordering = ('-date_joined',)
admin.site.unregister(User)
admin.site.register(User, CusUserAdmin)
参考:
https://docs.djangoproject.com/en/1.10/topics/auth/customizing/#writing-an-authentication-backend
https://stackoverflow.com/questions/11757172/django-admin-unique-email-verification-fails-against-self