|
问题
实际开发中可能内置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模型的扩展
可以从这些继承关系入手:
查看源码可以知道,User直接继承自AbstractUser,如果AbstractUser拥有的方法已经够用,且仅仅是添加一些额外字段的话,这是最方便的方法。
查看源码可以知道,AbstractUser继承自AbstractBaseUser与PermissionsMixin。这方法比方法1自定义程度更高,对已经使用User建表的情况不友好,因为会破坏已有的表结构,且还要自己写相关的权限验证,相当麻烦。
可以是可以,但直接改源码会在版本升级时失效。
不改变已有的表结构,且如果AbstractUser拥有的方法已经够用,仅需在已有表基础上添加额外字段,就可以将这些额外字段所在的表通过外键与 User 关联起来。
自定义一个继承自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 dependencyuser.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
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
来源:https://www.jb51.net/article/283886.htm
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|