首页 > 解决方案 > Django 尝试保存 AbstractUser 模型时出错

问题描述

我想将此 AbstractUser 保存在我的模型中。

#app_name members
#models.py
class User(AbstractUser):
        is_student = models.BooleanField(default=False)
        is_teacher = models.BooleanField(default=False)

设置.py

INSTALLED_APPS = [
 #deful django app...
 #others app....
 'members',

]

AUTH_USER_MODEL = 'members.User'

makemigrations 在出现此错误之前尝试保存时

django.core.management.base.SystemCheckError: SystemCheckError: System check identified some issues:

ERRORS:
auth.User.groups: (fields.E304) Reverse accessor for 'auth.User.groups' clashes with reverse accessor for 'members.User.groups'.        
        HINT: Add or change a related_name argument to the definition for 'auth.User.groups' or 'members.User.groups'.
auth.User.user_permissions: (fields.E304) Reverse accessor for 'auth.User.user_permissions' clashes with reverse accessor for 'members.User.user_permissions'.
        HINT: Add or change a related_name argument to the definition for 'auth.User.user_permissions' or 'members.User.user_permissions'.
members.User.groups: (fields.E304) Reverse accessor for 'members.User.groups' clashes with reverse accessor for 'auth.User.groups'.     
        HINT: Add or change a related_name argument to the definition for 'members.User.groups' or 'auth.User.groups'.
members.User.user_permissions: (fields.E304) Reverse accessor for 'members.User.user_permissions' clashes with reverse accessor for 'auth.User.user_permissions'.
        HINT: Add or change a related_name argument to the definition for 'members.User.user_permissions' or 'auth.User.user_permissions

为什么会出现这个错误?如何解决?

我也试过这个AUTH_USER_MODEL = 'myAppName.myClassName'并得到这个错误

django.core.management.base.SystemCheckError: SystemCheckError: System check identified some issues:

ERRORS:
blog.Blog.author: (fields.E301) Field defines a relation with the model 'auth.User', which has been swapped out.
        HINT: Update the relation to point at 'settings.AUTH_USER_MODEL'.
blog.BlogComment.user: (fields.E301) Field defines a relation with the model 'auth.User', which has been swapped out.
        HINT: Update the relation to point at 'settings.AUTH_USER_MODEL'.
blog.GlobalNotifications.user: (fields.E301) Field defines a relation with the model 'auth.User', which has been swapped out.
        HINT: Update the relation to point at 'settings.AUTH_USER_MODEL'.
notifications.Notifications.receiver: (fields.E301) Field defines a 
relation with the model 'auth.User', which has been swapped out.    
        HINT: Update the relation to point at 'settings.AUTH_USER_MODEL'.
notifications.Notifications.sender: (fields.E301) Field defines a relation with the model 'auth.User', which has been swapped out.      
        HINT: Update the relation to point at 'settings.AUTH_USER_MODEL'.

标签: django

解决方案


django.core.management.base.SystemCheckError: SystemCheckError: System check identified some issues:

ERRORS:
auth.User.groups: (fields.E304) Reverse accessor for 'auth.User.groups' clashes with reverse accessor for 'members.User.groups'.        
        HINT: Add or change a related_name argument to the definition for 'auth.User.groups' or 'members.User.groups'.
auth.User.user_permissions: (fields.E304) Reverse accessor for 'auth.User.user_permissions' clashes with reverse accessor for 'members.User.user_permissions'.
        HINT: Add or change a related_name argument to the definition for 'auth.User.user_permissions' or 'members.User.user_permissions'.
members.User.groups: (fields.E304) Reverse accessor for 'members.User.groups' clashes with reverse accessor for 'auth.User.groups'.     
        HINT: Add or change a related_name argument to the definition for 'members.User.groups' or 'auth.User.groups'.
members.User.user_permissions: (fields.E304) Reverse accessor for 'members.User.user_permissions' clashes with reverse accessor for 'auth.User.user_permissions'.
        HINT: Add or change a related_name argument to the definition for 'members.User.user_permissions' or 'auth.User.user_permissions

基本上这个错误是说你需要有 unqiue related_name 作为相关名称,以确保字段之间没有冲突。它找不到 settings.AUTH_USER_MODEL 因为你没有运行 makemigrations

如果你想用 is_student, is_teacher 创建自定义用户,你可以按照下面的代码,因为这就是我喜欢创建自定义用户的方式

您需要先运行 makemigrations 和 migrate 才能对其进行测试!或者您可以创建单独的应用程序以查看此自定义用户是否满足您的需求。

在 utils.py

from django.db import models
import random
from django.contrib.auth.base_user import BaseUserManager
from django.utils.translation import ugettext_lazy as _


class IntegerRangeField(models.IntegerField):
    """ 
      This model handels :
          - Creating custom IntegerField with min/ max value.
          - Used in Users class, employee_number.
          - Gives each employee exactly 4 digits integer.
          - Can be edited in future if company grows in size.
        ...
        Attributes:
        ----------
        min_value :
            minimum number.
        max_value:
            maximum number.
        Methods:
        formfield(self, **kwargs):
          - create new defaults for IntegerField then update them.
    """
    def __init__(self, verbose_name=None, name=None, min_value=None, max_value=None, **kwargs):
        self.min_value, self.max_value = min_value, max_value
        models.IntegerField.__init__(self, verbose_name, name, **kwargs)
    def formfield(self, **kwargs):
        defaults = {'min_value': self.min_value, 'max_value':self.max_value}
        defaults.update(kwargs)
        return super(IntegerRangeField, self).formfield(**defaults)

# generate random number from 1000, 9000

def create_new_employee_number():
    return random.randint(1000,9999)



class CustomUserManager(BaseUserManager):
    """
    Custom user model manager where username is unique identifiers
    able to add more fields to Django basic User model.
    """
    def create_student(self, username, password, **extra_fields):
        """
        Create and save a User with the given email and password.
        """
        if not username:
            raise ValueError(_('The username must be set'))
        user = self.model(username=username, **extra_fields)
        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, username, password, **extra_fields):
        """
        Create and save a SuperUser with the given email and password.
        """
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        extra_fields.setdefault('is_active', True)
        extra_fields.setdefault('is_student', False)
        extra_fields.setdefault('is_teacher', False)

        if extra_fields.get('is_staff') is not True:
            raise ValueError(_('Superuser must have is_staff=True.'))
        if extra_fields.get('is_superuser') is not True:
            raise ValueError(_('Superuser must have is_superuser=True.'))
        return self.create_user(username, password, **extra_fields)

    def create_teacher(self, username, first_name, last_name,  password=None):
        if not username:
            raise ValueError("User must have an email")
        if not password:
            raise ValueError("User must have a password")
        if not first_name:
            raise ValueError("User must have a first name")
        if not last_name:
            raise ValueError("User must have a last name")

        user = self.model(
            email=self.normalize_email(username)
        )
        user.first_name = first_name
        user.last_name = last_name
        user.set_password(password)  # change password to hash
        user.is_admin = False
        user.is_staff = True
        user.save(using=self._db)
        return user

    
    def create_staffuser(self, username, first_name, last_name,  password=None):
        if not username:
            raise ValueError("User must have an email")
        if not password:
            raise ValueError("User must have a password")
        if not first_name:
            raise ValueError("User must have a first name")
        if not last_name:
            raise ValueError("User must have a last name")

        user = self.model(
            email=self.normalize_email(username)
        )
        user.first_name = first_name
        user.last_name = last_name
        user.set_password(password)  # change password to hash
        user.is_admin = False
        user.is_staff = False
        user.is_teacher=True
        user.save(using=self._db)
        return user

现在在models.py


from django.db import models
from django.contrib.auth.models import AbstractUser
from django.db.models.signals import post_save, pre_save
from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ValidationError
import datetime
from .utils import (
    IntegerRangeField,
    CustomUserManager,
    create_new_employee_number
) 
ROLES_CHOICES = (
    ('ST', 'Student'),
    ('TC', 'Teacher')
)


class User(AbstractUser):
    """
      This model handels :
              - follows django docs on how to customizing user mode.
              - https://docs.djangoproject.com/en/3.2/topics/auth/customizing/
              - Creating new users into the database.
              - aumatically genearte JWT from the home/urls.py "rest_auth.registration.urls"
        ...
        Attributes:
        ----------
        username :
            unique string field, max_length is 50
        name:
            user first and last name.
        role:
            user role two options(ST: Student, TC: Teacher)
        id:
            unique randomly generated integer, editable by admin.
            uses custom field, more details about IntegerRangeField in utils.py
        Methods:
        __str__
            return a string repr of the user, username.
    """
    username = models.CharField(unique=True, max_length=50)
    name = models.CharField(max_length=50, blank=True, default="Employee")
    role = models.CharField(
        max_length=50, choices=ROLES_CHOICES,
        blank=False, null=False, default="ST",
        error_messages = {'invalid': "Role is two choices ADMIN or EM"}
       )
    id= IntegerRangeField(
        min_value=1000, max_value=9999, editable=True, blank=True,
        unique=True, default=create_new_employee_number,
        error_messages={'invalid': "employee_number is unique integer 1000-9999"}
        )

    objects = CustomUserManager()

    def __str__(self):
        return self.username


推荐阅读