阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Django使用自己的用户系统

88次阅读
没有评论

共计 7840 个字符,预计需要花费 20 分钟才能阅读完成。

用过 django 的人应该都会知道 admin, 不过,需求是多变的,比如,你有一个变态的用户系统,用户可能有大中小三张头像,除了 fisrt name ,last name 外还有 middle name,T^T name 巴拉巴拉,django 的用户系统可能满足不了你的需求,这时候需要用自己的用户系统了,如何能在满足需求的时候充分又利用到 django 的用户系统?

django 使用自己的用户系统
step-1 写自己的 auth 模块(定义 user class)
step-2 admin.py 注册到 django 的 admin 后台,并且修改一些 field
step-3 修改 settings.py 中相应配置

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/

Django 的详细介绍:请点这里
Django 的下载地址:请点这里

推荐阅读:

Ubuntu Server 12.04 安装 Nginx+uWSGI+Django 环境 http://www.linuxidc.com/Linux/2012-05/60639.htm

Django 实战教程 http://www.linuxidc.com/Linux/2013-09/90277.htm

Django Python MySQL Linux 开发环境搭建 http://www.linuxidc.com/Linux/2013-09/90638.htm

正文完
星哥说事-微信公众号
post-qrcode
 
星锅
版权声明:本站原创文章,由 星锅 2022-01-20发表,共计7840字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中