django.core.exceptions.ImproperlyConfigured: AUTH_USER_MODEL refers to model 'sso.User' that has not been installed
我出现的问题是在一个main.py 互相引用了user
look my demo:
from django.db import models #导入时间域 from django.utils import timezone # 懒加载可翻译 from django.utils.translation import gettext_lazy as _ # 引入 AbstractUser表,高级的功能/密码自动加密/检查密码 from django.contrib.auth.models import AbstractUser # 导入自定义重写注册用户的管理类 from sso.main import CustomUserManager #基类 class BaseModel(models.Model): #创建时间 create_time = models.DateTimeField(default=timezone.now, null=True) class Meta: abstract = True # 重写了原来User模型的表结构,所以必须第一次migrate前就先定义好 class User(AbstractUser): uid = models.BigIntegerField(primary_key=True, auto_created=True, unique=True, verbose_name=_('id全局标识')) email = models.CharField(unique=True, max_length=100, error_messages={'unique': _('此邮箱已被注册')}) # 额外的 mobile = models.CharField(unique=True, max_length=20, verbose_name=_('手机号')) avatar = models.ImageField( upload_to='avatar', #保存上传文件的目录 verbose_name='头像', #admin显示文字 null=True, blank=True, ) # 头像本地化处理 avatar_url = models.URLField( null=True, blank=True, verbose_name='头像地址', ) last_login_ip = models.CharField(max_length=40, blank=True, null=True) last_changepwd_time = models.DateTimeField(default=timezone.now, blank=True, null=True) original_pwd_change = models.PositiveIntegerField(default=0) USERNAME_FIELD = 'email' # 身份验证字段指向email,而不是原来的username REQUIRED_FIELDS = ['username'] # 注册admin用户提示选项 # 重新定义Manager对象,在创建user的时候使用 # email 和 password,而不是使用username和password objects = CustomUserManager() class Meta: managed = False db_table = 'authuser' verbose_name = '用户' verbose_name_plural = verbose_name def __str__(self): return self.email # 基于角色的权限管理,使用django-admin自带表,把group当作角色
接着问题来了,attention:
objects = CustomUserManager()
Yes,你必须在单独的.py中构造它,切记不能再里面引用User模型!!!
Like This Demo:
# Create your views here. # 引用用户注册管理类 from django.contrib.auth.models import UserManager # 雪花发号器 from sso.db.snowflake_tool import snowflakeid __all__ = ('CustomUserManager', ) # 自定义重写注册用户的管理类 class CustomUserManager(UserManager): use_in_migrations = True print('# # # Override the registered user management class UserManager to `CustomUserManager`') def _create_user(self, username, email, password, **extra_fields): """ Create and save a user with the given username, email, and password. """ if not email: raise ValueError('The given email must be set') # 使用雪花发号器 uid = snowflakeid() email = self.normalize_email(email) username = self.model.normalize_username(username) user = self.model(uid=uid, username=username, email=email, **extra_fields) user.set_password(password) user.save(using=self._db) return user
最后在admin.py,你可以写上有关它的扩展,
Like This Demo:
# Register your models here.
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
# 重新导入扩展后的user表
# from sso.models import User
# from django2education.settings import AUTH_USER_MODEL as User
from django.contrib.auth import get_user_model
User = get_user_model()
# 导入默认settings.AUTH_USER_MODEL
from django.contrib.auth.backends import ModelBackend
from django.db.models import Q, F
from sso.hashers import md5
admin.site.register(User, UserAdmin)
# 自定义用户身份认证类方法authenticate,配置到settings.py
# 支持用户名/手机/邮箱的用户认证
class CustomBackend(ModelBackend):
print("# # # The custom user authentication class `CustomBackend`")
@staticmethod
def authenticate(self, request, username=None, password=None, **kwargs):
try:
user = User.objects.get(Q(username=username) | Q(email=username) | Q(mobile=username))
# 统一前后端密码:由于获取vue前端的输入密码是已用md5加密,获取django-admin后台的输入密码是未加密
password = md5(password) if len(password) < 32 else password
if user.check_password(password):
return user
except Exception as e:
print(str(e))
return None
def get_user(self, uid):
try:
return User.objects.get(id=uid)
except Exception:
return None