django之对django内置的User模型进行自定义扩展方式

 更新时间:2023年05月10日 10:48:27   作者:dangfulin  
这篇文章主要介绍了django之对django内置的User模型进行自定义扩展方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

问题

实际开发中可能内置User模型的字段不能满足需要。

解决

1.首先查看内置User模型的源码:

MyDjango\venv\Scripts\pyton.exe\Lib\site-packages\django\contrib\auth\models.py,理清相关各类继承关系,如下:

class PermissionsMixin(models.Model):
class AbstractUser(AbstractBaseUser, PermissionsMixin):
class User(AbstractUser):

其中AbstractBaseUser在文件MyDjango\venv\Scripts\pyton.exe\Lib\site-packages\django\contrib\auth\base_user.py中:

class AbstractBaseUser(models.Model):

官方文档可以知道,User具有如下的内置方法:

class models.User
get_username()¶
Returns the username for the user. Since the User model can be swapped out, you should use this method instead of referencing the username attribute directly.
get_full_name()¶
Returns the first_name plus the last_name, with a space in between.
get_short_name()¶
Returns the first_name.
set_password(raw_password)¶
Sets the user's password to the given raw string, taking care of the password hashing. Doesn't save the User object.
When the raw_password is None, the password will be set to an unusable password, as if set_unusable_password() were used.
check_password(raw_password)¶
Returns True if the given raw string is the correct password for the user. (This takes care of the password hashing in making the comparison.)
set_unusable_password()¶
Marks the user as having no password set. This isn't the same as having a blank string for a password. check_password() for this user will never return True. Doesn't save the User object.
You may need this if authentication for your application takes place against an existing external source such as an LDAP directory.
has_usable_password()¶
Returns False if set_unusable_password() has been called for this user.
Changed in Django 2.1:
In older versions, this also returns False if the password is None or an empty string, or if the password uses a hasher that's not in the PASSWORD_HASHERS setting. That behavior is considered a bug as it prevents users with such passwords from requesting a password reset.
get_group_permissions(obj=None)¶
Returns a set of permission strings that the user has, through their groups.
If obj is passed in, only returns the group permissions for this specific object.
get_all_permissions(obj=None)¶
Returns a set of permission strings that the user has, both through group and user permissions.
If obj is passed in, only returns the permissions for this specific object.
has_perm(perm, obj=None)¶
Returns True if the user has the specified permission, where perm is in the format "<app label>.<permission codename>". (see documentation on permissions). If the user is inactive, this method will always return False.
If obj is passed in, this method won't check for a permission for the model, but for this specific object.
has_perms(perm_list, obj=None)¶
Returns True if the user has each of the specified permissions, where each perm is in the format "<app label>.<permission codename>". If the user is inactive, this method will always return False.
If obj is passed in, this method won't check for permissions for the model, but for the specific object.
has_module_perms(package_name)¶
Returns True if the user has any permissions in the given package (the Django app label). If the user is inactive, this method will always return False.
email_user(subject, message, from_email=None, **kwargs)¶
Sends an email to the user. If from_email is None, Django uses the DEFAULT_FROM_EMAIL. Any **kwargs are passed to the underlying send_mail() call.

从源码可以知道,它们来自PermissionsMixin类、AbstractBaseUser类和AbstractUser类。

2.因此要实现内置User模型的扩展

可以从这些继承关系入手:

  • 1 继承AbstractUser

查看源码可以知道,User直接继承自AbstractUser,如果AbstractUser拥有的方法已经够用,且仅仅是添加一些额外字段的话,这是最方便的方法。

  • 2 继承AbstractBaseUser

查看源码可以知道,AbstractUser继承自AbstractBaseUser与PermissionsMixin。这方法比方法1自定义程度更高,对已经使用User建表的情况不友好,因为会破坏已有的表结构,且还要自己写相关的权限验证,相当麻烦。

  • 3 重写User源码

可以是可以,但直接改源码会在版本升级时失效。

  • 4 使用Profile模式

不改变已有的表结构,且如果AbstractUser拥有的方法已经够用,仅需在已有表基础上添加额外字段,就可以将这些额外字段所在的表通过外键与 User 关联起来。

  • 5 设置Proxy模型

自定义一个继承自User的类,将元数据Meta中的proxy置为True,以代表这个是User的代理模型。适用于不改变已有的表结构,但对User拥有的方法不够满足而需要自定义方法的情况。

大多情况下会选择方法1,既不改变原有User结构,也不会额外建表。

如下:

from django.db import models
from django.contrib.auth.models import AbstractUser
class MyUser(AbstractUser):
    qq = models.CharField('QQ号', max_length=30)
    wechat = models.CharField('微信号', max_length=40)
    mobile = models.CharField('电话号', max_length=20)
    class Meta:
        verbose_name_plural = '自定义用户表'
    def __str__(self):
        return self.username

记得在settings.py添加:

AUTH_USER_MODEL = '应用名.扩展的类名'

最后要进行数据迁移:

python manage.py makemigrations
python manage.py migrate

可能会报错:

django.db.migrations.exceptions.InconsistentMigrationHistory:
Migration admin.0001_initial is applied bef ore its dependency
user.0001_initial on database ‘default’.

删除数据库中除auth_user外的其他表,再重新进行数据迁移即可。

结果如下:

进入admin后台系统,但却没显示MyUser信息表。

根据MyUser的产生原理可以知道,MyUser是在User的model.py中定义的,admin后台无法直接显示MyUser信息表,需要在项目的admin.py与__init__.py中进行相关定义:

admin.py:
from django.contrib import admin
from .models import MyUser
from django.contrib.auth.admin import UserAdmin
from django.utils.translation import gettext_lazy as _
# 先注册
@admin.register(MyUser)
class MyUserAdmin(UserAdmin):
    list_display = ['username', 'email', 'mobile', 'qq', 'wechat']
    # 将源码的UserAdmin.fieldsets转换成列表格式
    fieldsets = list(UserAdmin.fieldsets)
    fieldsets[1] = (_('Personal info'),
                    {'fields': ('first_name', 'last_name',
                     'email', 'mobile', 'qq', 'wechat')})
__init__.py:
from django.apps import AppConfig
import os
default_app_config = 'user.IndexConfig'
# 获取当前app的命名
def get_current_app_name(_file):
    return os.path.split(os.path.dirname(_file))[-1]
# 重写类IndexConfig
class IndexConfig(AppConfig):
    name = get_current_app_name(__file__)
    verbose_name = '自定义用户信息数据表'

MyUserAdmin继承自UserAdmin,再重写后台数据展示字段,就能使自定义用户模型展示在admin后台。

然后运行开发服务器,可能会报错:

LookupError: No installed app with label ‘admin’.

我的django版本为2.2,查了一下,据说是2.2的bug,更换为2.2.14后问题解决。

如下:

访问127.0.0.1:8000

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • django 多数据库配置教程

    django 多数据库配置教程

    今天小编就为大家分享一篇django 多数据库配置教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-05-05
  • Numpy之random函数使用学习

    Numpy之random函数使用学习

    这篇文章主要介绍了Numpy之random使用学习,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-01-01
  • Python常用算法学习基础教程

    Python常用算法学习基础教程

    这篇文章主要学习Python常用算法,Python常用排序算法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一
    2017-04-04
  • 我用Python给班主任写了一个自动阅卷脚本(附源码)

    我用Python给班主任写了一个自动阅卷脚本(附源码)

    这篇文章主要介绍了如何用Python给写了一个自动阅卷脚本,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-08-08
  • python读取csv文件并把文件放入一个list中的实例讲解

    python读取csv文件并把文件放入一个list中的实例讲解

    下面小编就为大家分享一篇python读取csv文件并把文件放入一个list中的实例讲解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-04-04
  • Python科学计算之Pandas详解

    Python科学计算之Pandas详解

    Pandas 是 python 的一个数据分析包,属于PyData项目的一部分。下面这篇文章主要介绍了Python中科学计算之Pandas,需要的朋友可以参考借鉴,下面来一起学习学习。
    2017-01-01
  • python中的Pytorch建模流程汇总

    python中的Pytorch建模流程汇总

    这篇文章主要介绍了python中的Pytorch建模流程汇总,主要帮大家帮助大家梳理神经网络训练的架构,具有一的的参考价值,需要的小伙伴可以参考一下,希望对你的学习有所帮助
    2022-03-03
  • Python常用模块之datetime模块详解

    Python常用模块之datetime模块详解

    这篇文章主要介绍了Python常用模块之datetime模块详解,datetime是Python处理日期和时间的标准库,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-08-08
  • python脚本之如何按照清晰度对图片进行分类

    python脚本之如何按照清晰度对图片进行分类

    这篇文章主要介绍了python脚本之如何按照清晰度对图片进行分类问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • python读取二进制mnist实例详解

    python读取二进制mnist实例详解

    这篇文章主要介绍了python读取二进制mnist实例详解的相关资料,需要的朋友可以参考下
    2017-05-05

最新评论