Django框架之重载Admin用户系统

前言

这几年一直在it行业里摸爬滚打,一路走来,不少总结了一些python行业里的高频面试,看到大部分初入行的新鲜血液,还在为各样的面试题答案或收录有各种困难问题

于是乎,我自己开发了一款面试宝典,希望能帮到大家,也希望有更多的Python新人真正加入从事到这个行业里,让python火不只是停留在广告上。

微信小程序搜索:Python面试宝典

或可关注原创个人博客:https://lienze.tech

也可关注微信公众号,不定时发送各类有趣猎奇的技术文章:Python编程学习

重载admin用户系统

django自带的admin模块下的用户系统主要负责用户账户,组,权限和基于cookie的会话等业务

认证系统由以下部分组成:

  • 用户:包含用户数据字段,是实现业务功能逻辑的基础

  • 权限:控制用户进否可以执行某项任务的二进制(是/否)标志。

  • 组:一种为多个用户加上标签和权限的常用方式。

  • 消息:一种为指定用户生成简单消息队列的方式

默认方法

在项目中,我们将使用email作为用户的用户名,那么可以在自带用户表中写明

USERNAME_FIELD = 'email'
# 该属性设置当前表的登陆字段

描述我们自定义用户模型上作唯一标识符字段名称的字符串,字段必须是唯一的,在定义中设置

unique=True

设置某个字段为必填项

REQUIRED_FIELDS = ['username']

  • is_authenticated()

判断用户是否已通过身份验证的方法,不意味任何权限,而且不检查用户的活动状态

  • get_username()

返回由USERNAME_FIELD制定的字段的值

  • get_full_name()

返回first_name加上last_name

中间加上一个空格,由于我们重新设置了表字段,那么这个默认函数需要我们重新给定返回值

  • get_short_name()

一个短的且非正式用户的标识符,返回first_name

当你的项目重写该字段或直接去掉了first_name,所以我们必须重新给定这个函数的返回值

  • set_password()

将用户的密码设置为给定的字符串

  • has_perm(perm, obj=None)

用户是否具有某个权限,如果给定obj,则需要根据特定对象实例检查权限

  • has_module_perms(app_label)

如果用户有权访问给定应用中的模型,则返回True

这里我们这两个字段都设置为True,可以让用户访问任一APP

  • is_staff()@property

如果用户允许访问管理网站,则返回True

这里我们返回is_admin的字段属性即可


关于字段属性,如果需要进行高度扩展,可以使用继承AbstractBaseUser这个类

这个类中只含有passwordlast_login,以及is_active三个字段属性

重载管理器

由于已经覆盖了默认的admin用户表,现在需要将其对应的管理器函数进行编写

编写时主要关注一下两个父类函数的重写

create_user(username_field,password_filed=None,**other_fields)
	normalize_email()将邮件地址规范化的类方法
	user.save(using=self._db)
create_superuser(username, email, password)
	#用户创建,is_admin设置为True即可
    user.save(using=self._db)
from django.contrib.auth.models import BaseUserManager
class MyUserManager(BaseUserManager):
    def create_user(self, username, email, password=None):
        if not email :
            raise ValueError('Users must have an email address')
        if not username:
            raise ValueError('Users must have an username')
        #判断邮件和用户名是否具有
        now = timezone.now()
        #获取当前django的时间
        user = self.model(
            username=username,
            email=self.normalize_email(email),
            date_joined=now, 
            last_login=now,
        )
        user.set_password(password)
        user.save(using=self._db)
        return user
        
    def create_superuser(self, username, email, password):
        user = self.create_user(username,
            email,
            password=password,
        )
        user.is_admin = True
        user.save(using=self._db)
        return user

重新定义新用户表的管理器之后,想要生效,还需要在对应的模型类表中覆盖objects属性

  • objects = MyUserManager()

重载表

下面是一个真实的重载自带用户表的模型类

from django.contrib.auth.models import AbstractBaseUser
class Member(AbstractBaseUser):
    #AbstractBaseUser中只含有3个field: password, last_login和is_active.
    email = models.EmailField(verbose_name='邮箱',max_length=255,unique=True,)
    username = models.CharField(verbose_name="用户名", max_length=16, unique=True)
    weibo_id = models.CharField(verbose_name="新浪微博", max_length=30, blank=True)
    blog = models.CharField(verbose_name="个人网站", max_length=200, blank=True)
    location = models.CharField(verbose_name="城市", max_length=10, blank=True)
    profile = models.CharField(verbose_name="个人简介", max_length=140, blank=True)
    avatar = models.CharField(verbose_name="头像", max_length=128, blank=True)
    au = models.IntegerField(verbose_name="用户活跃度", default=0)
    last_ip = models.IPAddressField(verbose_name="上次访问IP", default="0.0.0.0")
    email_verified = models.BooleanField(verbose_name="邮箱是否验证", default=False)
    date_joined = models.DateTimeField(verbose_name="用户注册时间", default=timezone.now)


    topic_num = models.IntegerField(verbose_name="帖子数", default=0)
    comment_num = models.IntegerField(verbose_name="评论数", default=0)
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    objects = MyUserManager()
    #objects就是我们之前一直使用的管理器
    #管理器用来维护我们的增删改查

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username']

    def __str__(self):
        return self.username
    #标签中的数据实例
    def is_email_verified(self):
        return self.email_verified
    #我们可以在模板中,通过实例出来的对象数据进行这个函数的调取,获取他是否验证过
    def get_weibo(self):
        return self.weibo_id

    def get_username(self):
        return self.username
        #方法的圆括号在templates标签中必需省略!!
    def get_email(self):
        return self.email
        #方法的圆括号在templates标签中必需省略!!

    def get_full_name(self):
        # The user is identified by their email address
        return self.email
        #get_full_name本来是获取first_name和last_name的
        #但是由于我们重新设置了表结构,那么这个函数必须自定义
        #方法的圆括号在templates标签中必需省略!!

    def get_short_name(self):
        # The user is identified by their email address
        return self.username

    def has_perm(self, perm, obj=None):
        "Does the user have a specific permission?"
        return True

    def has_module_perms(self, app_label):
        "Does the user have permissions to view the app `app_label`?"
        return True

    def calculate_au(self):
        """
        计算活跃度
        公式:Topic * 5 + Comment * 1
        """
        self.au = self.topic_num * 5 + self.comment_num * 1
        return self.au

    @property
    #类中函数可以直接做为属性使用
    def is_staff(self):
        "Is the user a member of staff?"
        # Simplest possible answer: All admins are staff
        return self.is_admin

重载Admin表单

由于修改了默认的django表结构,此时在admin界面修改密码或添加用户数据已经不能再按照之前的表单系统啦

需要在appadmin.py中重写UserCreationFormUserChangeForm

# 用户创建表单
from django import forms
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from people.models import Member, Follower


class UserCreationForm(forms.ModelForm):
    """A form for creating new users. Includes all the required
    fields, plus a repeated password."""
    password1 = forms.CharField(label='密码', widget=forms.PasswordInput)
    password2 = forms.CharField(label='确认密码', widget=forms.PasswordInput)
    class Meta:
        model = Member
        fields = ('email', 'username')

    def clean_password2(self):
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError("两次输入验证失败")
        return password2
        
    #在form中的clean__field函数会在is_valid()函数验证时自动调用
    def save(self, commit=True):
        user = super(UserCreationForm, self).save(commit=False)
        user.set_password(self.cleaned_data["password1"])
        #set_password将会采用django的加密算法将密码设置到对应的模型实例中
        #在内存中创建的好的对象只有通过commit=True才被真正执行到数据库上
        if commit:
            user.save()
        return user
# 密码改变时的展示表单
class UserChangeForm(forms.ModelForm):
    password = ReadOnlyPasswordHashField()
    class Meta:
        model = Member
        fields = ('email', 'password', 'username', 'is_active', 'is_admin',)
    def clean_password(self):
        return self.initial["password"]
    #使用默认的save函数即可
# 真正的用户admin界面管理方式
class MyUserAdmin(UserAdmin):
    form = UserChangeForm
    add_form = UserCreationForm
    list_display = ('id', 'email', 'username', 'email_verified', 'last_login','is_active','is_admin','last_ip')
    list_display_links = ('id', 'email', 'username')
    list_filter = ('email', 'email_verified',)
    fieldsets = (
        (None, {
    
    'fields': ('username', 'email', 'date_joined', 'password','is_active','is_admin','avatar')}),
        ('状态', {
    
    'fields': ('email_verified', 'last_ip', 'au', 'topic_num', 'comment_num')}),
        ('社交网络', {
    
    'fields': ('weibo_id', 'blog')}),
    )
    add_fieldsets = (
        (None, {
    
    
            'classes': ('wide',),
            #admin样式设置
            #Fieldsets 使用 wide 样式将会有额外的水平空格.
            'fields': ('email', 'username', 'password1', 'password2','is_active','is_admin')}
        ),
    )
    search_fields = ('id', 'email', 'username')
    ordering = ('id', 'email', 'email_verified')
    filter_horizontal = ()
    #这个字段为了设置与groups关联的多选框
admin.site.register(Member, MyUserAdmin)
admin.site.register(Follower)

最终

还需要在settings.py文件下进行设置,覆盖默认的User模型

  • AUTH_USER_MODEL = 'people.Member'

猜你喜欢

转载自blog.csdn.net/HeroicLee/article/details/121406603