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

总结

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

相关文章

  • pycharm远程连接vagrant虚拟机中mariadb数据库

    pycharm远程连接vagrant虚拟机中mariadb数据库

    这篇文章主要介绍了pycharm远程连接vagrant虚拟机中mariadb数据库,需要的朋友可以参考下
    2020-06-06
  • 一步步教你用python连接oracle数据库

    一步步教你用python连接oracle数据库

    oracle作为最强大的数据库,Python也提供了足够的支持。不过与其他数据库略有不同,下面这篇文章主要给大家介绍了关于如何使用python连接oracle数据库的相关资料,需要的朋友可以参考下
    2023-04-04
  • python3 使用Opencv打开USB摄像头,配置1080P分辨率的操作

    python3 使用Opencv打开USB摄像头,配置1080P分辨率的操作

    今天小编就为大家分享一篇python3 使用Opencv打开USB摄像头,配置1080P分辨率的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-12-12
  • 教你用Python下载抖音无水印视频

    教你用Python下载抖音无水印视频

    这篇文章主要介绍了教你用Python下载抖音无水印视频,文中有非常详细的代码示例,对正在学习python的小伙伴们有很好地帮助,需要的朋友可以参考下
    2021-05-05
  • python解析xml文件并修改其属性值方式

    python解析xml文件并修改其属性值方式

    本文介绍了两种解析和修改XML文件的方法:使用Python自带的xml.etree.ElementTree和第三方的lxml,lxml方法可以添加standalone属性,而ElementTree则不能
    2025-02-02
  • Flask带参URL传值的实现方法

    Flask带参URL传值的实现方法

    这篇文章主要介绍了Flask带参URL传值的实现方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • python nohup 实现远程运行不宕机操作

    python nohup 实现远程运行不宕机操作

    这篇文章主要介绍了python nohup 实现远程运行不宕机操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-04-04
  • python创建列表并给列表赋初始值的方法

    python创建列表并给列表赋初始值的方法

    这篇文章主要介绍了python创建列表并给列表赋初始值的方法,涉及Python列表的定义与赋值技巧,需要的朋友可以参考下
    2015-07-07
  • Python3 翻转二叉树的实现

    Python3 翻转二叉树的实现

    这篇文章主要介绍了Python3 翻转二叉树的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • Python代码块批量添加Tab缩进的方法

    Python代码块批量添加Tab缩进的方法

    今天小编就为大家分享一篇Python代码块批量添加Tab缩进的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-06-06

最新评论