django使用自己的用户系统
用过django的人应该都会知道admin,什么,真的没用过?汗,如果这样的话先看看这个
https://docs.djangoproject.com/en/1.6/ref/contrib/admin/
django自带用户系统,通过上面的admin,以及auth可以方便的管理用户。
不过,需求是多变的,比如,你有一个变态的用户系统,用户可能有大中小三张头像,
除了fisrt name ,last name外还有middle name,T^T name巴拉巴拉,django
的用户系统可能满足不了你的需求,这时候需要用自己的用户系统了,如何能在满足
需求的时候充分又利用到django的用户系统?
官方文档如下,内有详细说明,有英文厌烦症的可以直接略过
https://docs.djangoproject.com/en/dev/topics/auth/customizing/
其实步骤很简单
- 写自己的auth模块(定义user class);
- admin.py 注册到django的admin后台,并且修改一些field
- 修改settings.py中相应配置
step-1 写自己的auth模块(定义user class)
新建一个模块,名字随意,假设叫做myauth
User class继承AbstractBaseUser,UserManager继承BaseUserManager
重写对应的方法,建议浏览下AbstractBaseUser, BaseUserManager的源码
User类不用说,也就是根据自己业务定义的用户class,Manager就是django中
的Manager,做的事情你肯定经常用到,obj.objects.filter(),其中的objects
就是Manager,文档如下
https://docs.djangoproject.com/en/dev/topics/db/managers/
code
# -*- coding: utf-8 -*-
from django.db import models
from django.contrib.auth.models import (BaseUserManager, AbstractBaseUser)
class UserManager(BaseUserManager):
def create_user(self, name, email, password=None):
if not email:
raise ValueError('Users must have an email address')
user = self.model(
name=name,
email=UserManager.normalize_email(email),
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, name, email, password=None):
user = self.create_user(name, email, password)
user.is_admin = True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
'''用户表'''
name = models.CharField(max_length=100, unique=True)
email = models.EmailField(max_length=100, unique=True)
avatar = models.URLField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_delete = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
access_token = models.CharField(max_length=100, blank=True)
refresh_token = models.CharField(max_length=100, blank=True)
expires_in = models.BigIntegerField(max_length=100, default=0)
objects = UserManager()
USERNAME_FIELD = 'name'
REQUIRED_FIELDS = ('email',)
class Meta:
ordering = ('-created_at',)
def __unicode__(self):
return self.name
def get_full_name(self):
return self.email
def get_short_name(self):
return self.name
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
@property
def is_staff(self):
return self.is_admin
重写的字段看下源码就可以解释到了:
1. AbstractBaseUser已经有password, last_login,所以密码这些就不用费心了
2. 由于get_username用到了self.USERNAME_FIELD,所以需要指明哪个字段为用户名
3. get_short_name,get_full_name需要实现,否则会抛异常
4. 其他就按照自己的业务来写即可
5. UserManager重写下两个create方法
class AbstractBaseUser(models.Model):
password = models.CharField(_('password'), max_length=128)
last_login = models.DateTimeField(_('last login'), default=timezone.now)
is_active = True
REQUIRED_FIELDS = []
class Meta:
abstract = True
def get_username(self):
"Return the identifying username for this User"
return getattr(self, self.USERNAME_FIELD)
def __str__(self):
return self.get_username()
def natural_key(self):
return (self.get_username(),)
def is_anonymous(self):
"""
Always returns False. This is a way of comparing User objects to
anonymous users.
"""
return False
def is_authenticated(self):
"""
Always return True. This is a way to tell if the user has been
authenticated in templates.
"""
return True
def set_password(self, raw_password):
self.password = make_password(raw_password)
def check_password(self, raw_password):
"""
Returns a boolean of whether the raw_password was correct. Handles
hashing formats behind the scenes.
"""
def setter(raw_password):
self.set_password(raw_password)
self.save(update_fields=["password"])
return check_password(raw_password, self.password, setter)
def set_unusable_password(self):
# Sets a value that will never be a valid hash
self.password = make_password(None)
def has_usable_password(self):
return is_password_usable(self.password)
def get_full_name(self):
raise NotImplementedError()
def get_short_name(self):
raise NotImplementedError()
step-2 admin.py 注册到django的admin后台,并且修改一些field
admin注册user,参考文档 https://docs.djangoproject.com/en/dev/ref/contrib/admin/
代码如下,感觉没什么需要说明的。
myauth/admin.py
#coding: utf-8
from django import forms
from django.contrib import admin
from django.contrib.auth.models import Group as DjangoGroup
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from myauth.models import User
# 新增用户表单
class UserCreateForm(forms.ModelForm):
"""A form for creating new users. Includes all the required
fields, plus a repeated password."""
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(
label='Password confirmation',
widget=forms.PasswordInput,
)
class Meta:
model = User
fields = ('name', 'email')
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserCreateForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
# 修改用户表单
class UserChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = User
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]
# 注册用户
class MyUserAdmin(UserAdmin):
form = UserChangeForm
add_form = UserCreateForm
list_display = ('name', 'created_at', 'email', 'is_delete', 'is_admin')
search_fields = ('name', 'email')
list_filter = ('is_admin',)
readonly_fields = ('created_at', 'updated_at')
fieldsets = (
(None, {'fields': ('name', 'email', 'password', 'avatar',)}),
('Personal info', {'fields': ('created_at', 'updated_at')}),
(
'Open token info',
{
'fields': ('access_token', 'refresh_token', 'expires_in')
}
),
('Permissions', {'fields': ('is_delete', 'is_admin', 'is_active')}),
('Important dates', {'fields': ('last_login',)}),
)
add_fieldsets = (
(
None,
{
'classes': ('wide',),
'fields': ('name', 'email', 'password1', 'password2'),
}
),
)
ordering = ('created_at',)
filter_horizontal = ()
admin.site.register(User, MyUserAdmin)
step-3 修改settings.py中相应配置
添加 AUTH_USER_MODEL = ‘myauth.User’
install_app不要忘记加上myauth模块
grep django的源码可以看到,很多地方直接使用了配置AUTH_USER_MODEL
user = models.ForeignKey(settings.AUTH_USER_MODEL)
def get_user_model():
"""
Returns the User model that is active in this project.
"""
from django.db.models import get_model
try:
app_label, model_name = settings.AUTH_USER_MODEL.split('.')
except ValueError:
raise ImproperlyConfigured("AUTH_USER_MODEL must be of the form 'app_label.model_name'")
user_model = get_model(app_label, model_name)
if user_model is None:
raise ImproperlyConfigured("AUTH_USER_MODEL refers to model '%s' that has not been installed" % settings.AUTH_USER_MODEL)
return user_model
ps: django admin更改主题,django admin的主题实在是太朴素了
https://riccardo.forina.me/bootstrap-your-django-admin-in-3-minutes/