django之對django內(nèi)置的User模型進行自定義擴展方式
問題
實際開發(fā)中可能內(nèi)置User模型的字段不能滿足需要。
解決
1.首先查看內(nèi)置User模型的源碼:
MyDjango\venv\Scripts\pyton.exe\Lib\site-packages\django\contrib\auth\models.py,理清相關(guān)各類繼承關(guān)系,如下:
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具有如下的內(nèi)置方法:
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.因此要實現(xiàn)內(nèi)置User模型的擴展
可以從這些繼承關(guān)系入手:
- 1 繼承AbstractUser
查看源碼可以知道,User直接繼承自AbstractUser,如果AbstractUser擁有的方法已經(jīng)夠用,且僅僅是添加一些額外字段的話,這是最方便的方法。
- 2 繼承AbstractBaseUser
查看源碼可以知道,AbstractUser繼承自AbstractBaseUser與PermissionsMixin。這方法比方法1自定義程度更高,對已經(jīng)使用User建表的情況不友好,因為會破壞已有的表結(jié)構(gòu),且還要自己寫相關(guān)的權(quán)限驗證,相當(dāng)麻煩。
- 3 重寫User源碼
可以是可以,但直接改源碼會在版本升級時失效。
- 4 使用Profile模式
不改變已有的表結(jié)構(gòu),且如果AbstractUser擁有的方法已經(jīng)夠用,僅需在已有表基礎(chǔ)上添加額外字段,就可以將這些額外字段所在的表通過外鍵與 User 關(guān)聯(lián)起來。
- 5 設(shè)置Proxy模型
自定義一個繼承自User的類,將元數(shù)據(jù)Meta中的proxy置為True,以代表這個是User的代理模型。適用于不改變已有的表結(jié)構(gòu),但對User擁有的方法不夠滿足而需要自定義方法的情況。
大多情況下會選擇方法1,既不改變原有User結(jié)構(gòu),也不會額外建表。
如下:
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 = '應(yīng)用名.擴展的類名'
最后要進行數(shù)據(jù)遷移:
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’.
刪除數(shù)據(jù)庫中除auth_user外的其他表,再重新進行數(shù)據(jù)遷移即可。
結(jié)果如下:
進入admin后臺系統(tǒng),但卻沒顯示MyUser信息表。
根據(jù)MyUser的產(chǎn)生原理可以知道,MyUser是在User的model.py中定義的,admin后臺無法直接顯示MyUser信息表,需要在項目的admin.py與__init__.py中進行相關(guān)定義:
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轉(zhuǎn)換成列表格式 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' # 獲取當(dāng)前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 = '自定義用戶信息數(shù)據(jù)表'
MyUserAdmin繼承自UserAdmin,再重寫后臺數(shù)據(jù)展示字段,就能使自定義用戶模型展示在admin后臺。
然后運行開發(fā)服務(wù)器,可能會報錯:
LookupError: No installed app with label ‘admin’.
我的django版本為2.2,查了一下,據(jù)說是2.2的bug,更換為2.2.14后問題解決。
如下:
訪問127.0.0.1:8000
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Numpy之random函數(shù)使用學(xué)習(xí)
這篇文章主要介紹了Numpy之random使用學(xué)習(xí),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-01-01Python常用算法學(xué)習(xí)基礎(chǔ)教程
這篇文章主要學(xué)習(xí)Python常用算法,Python常用排序算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一2017-04-04python讀取csv文件并把文件放入一個list中的實例講解
下面小編就為大家分享一篇python讀取csv文件并把文件放入一個list中的實例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-04-04