CommandError:此字段不能为空。该字段不能为空。创建超级用户时

问题描述 投票:0回答:1

我使用自定义用户进行 Django 身份验证,每次尝试创建超级用户时,标题中都会出现错误。 更令人困惑的是,用户似乎已注册,因为当我尝试在下一次创建中使用该电子邮件时,它说该电子邮件已被使用,但当我尝试登录时,它说该用户没有个人资料。

用户模型有以下代码:

from typing import ClassVar
from django.utils import timezone

from django.contrib.auth.models import AbstractBaseUser,PermissionsMixin, Group, Permission
from django.db import models
from django.db.models import BooleanField
from django.db.models import CharField
from django.db.models import EmailField
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from rhs_soccer.users.enums import UserRoles

from .managers import UserManager


class User(AbstractBaseUser, PermissionsMixin):
    """
    Default custom user model for RHS Boys Soccer Club.
    If adding fields that need to be filled at user signup,
    check forms.SignupForm and forms.SocialSignupForms accordingly.
    """

    # First and last name do not cover name patterns around the globe
    #id = models.UUIDField(default=uuid.uuid4, primary_key = True, editable=False, unique=True)    
    first_name = CharField(_("first name"), max_length=30, blank = True, null = True)
    last_name = CharField(_("last name"), max_length=30, blank = True,  null = True)
    email = EmailField(_("email address"), unique=True)
    role = CharField(
        _("Role"),
        max_length=50,
        choices=UserRoles.choices(),
        default=UserRoles.PLAYER.value,
    )
    username = None  # type: ignore[assignment]
    is_active = BooleanField(_("active"), default=True)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    groups = models.ManyToManyField(
        Group,
        related_name="user_set",
        related_query_name="user",
        blank=True,
    )
    user_permissions = models.ManyToManyField(
        Permission,
        related_name="user_set",
        related_query_name="user",
        blank=True,
    )
    date_joined = models.DateTimeField(default=timezone.now)
    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = []

    objects: ClassVar[UserManager] = UserManager()

    def get_absolute_url(self) -> str:
        """Get URL for user's detail view.

        Returns:
            str: URL for user detail.

        """
        return reverse("users:detail", kwargs={"pk": self.id})

    def __str__(self) -> str:
        return self.email

    def get_full_name(self) -> str:
        return f"{self.first_name} {self.last_name}"

The user managers.py file has the following code:
from typing import TYPE_CHECKING

from django.contrib.auth.hashers import make_password
from django.contrib.auth.models import BaseUserManager
from django.utils import timezone
# from django.contrib.auth.models import UserManager as DjangoUserManager

if TYPE_CHECKING:
    from .models import User  # noqa: F401


class UserManager(BaseUserManager):
    """Custom manager for the User model."""

    def _create_user(self, email: str, password: str | None, **extra_fields):
        """
        Create and save a user with the given email and password.
        """
        if not email:
            msg = "The given email must be set"
            raise ValueError(msg)
        email = self.normalize_email(email)
        extra_fields.setdefault('date_joined', timezone.now())
        user = self.model(email=email, **extra_fields)
        user.password = make_password(password)
        user.save(using=self._db)
        return user

    def create_user(self, email: str, password: str | None = None, **extra_fields):  # type: ignore[override]
        extra_fields.setdefault("is_staff", True)
        extra_fields.setdefault("is_superuser", False)
        return self._create_user(email, password, **extra_fields)

    def create_player(self, email: str, password: str | None = None, **extra_fields):  # type: ignore[override]
        extra_fields.setdefault("is_staff", False)
        extra_fields.setdefault("is_superuser", False)
        extra_fields.setdefault("role", "PLAYER")
        return self._create_user(email, password, **extra_fields)

    def create_coach(self, email: str, password: str | None = None, **extra_fields):  # type: ignore[override]
        extra_fields.setdefault("is_staff", False)
        extra_fields.setdefault("is_superuser", False)
        extra_fields.setdefault("role", "COACH")
        return self._create_user(email, password, **extra_fields)

    def create_manager(self, email: str, password: str | None = None, **extra_fields):  # type: ignore[override]
        extra_fields.setdefault("is_staff", False)
        extra_fields.setdefault("is_superuser", False)
        extra_fields.setdefault("role", "MANAGER")
        return self._create_user(email, password, **extra_fields)

    def create_parent(self, email: str, password: str | None = None, **extra_fields):  # type: ignore[override]
        extra_fields.setdefault("is_staff", False)
        extra_fields.setdefault("is_superuser", False)
        extra_fields.setdefault("role", "PARENT")
        return self._create_user(email, password, **extra_fields)

    def create_admin(self, email: str, password: str | None = None, **extra_fields):  # type: ignore[override]
        extra_fields.setdefault("is_staff", True)
        extra_fields.setdefault("is_superuser", True)
        extra_fields.setdefault("role", "ADMIN")
        return self._create_user(email, password, **extra_fields)

    def create_superuser(self, email: str, password: str | None = None, **extra_fields):  # type: ignore[override]
        extra_fields.setdefault("is_staff", True)
        extra_fields.setdefault("is_superuser", True)
        extra_fields.setdefault("role", "ADMIN")

        if 'first_name' not in extra_fields:
            extra_fields['first_name'] = ''
        if 'last_name' not in extra_fields:
            extra_fields['last_name'] = ''
        if extra_fields.get("is_staff") is not True:
            msg = "Superuser must have is_staff=True."
            raise ValueError(msg)
        if extra_fields.get("is_superuser") is not True:
            msg = "Superuser must have is_superuser=True."
            raise ValueError(msg)

        return self._create_user(email, password, **extra_fields)

The forms.py has the following code:
from allauth.account.forms import SignupForm
from allauth.socialaccount.forms import SignupForm as SocialSignupForm
from django.contrib.auth import forms as admin_forms
from django.forms import EmailField
from django.utils.translation import gettext_lazy as _
from django import forms
from .models import User


class UserAdminChangeForm(admin_forms.UserChangeForm):
    class Meta(admin_forms.UserChangeForm.Meta):  # type: ignore[name-defined]
        model = User
        fields = ('email', 'first_name', 'last_name', 'role', 'is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions')
        field_classes = {"email": EmailField}


class UserAdminCreationForm(admin_forms.UserCreationForm):
    """
    Form for User Creation in the Admin Area.
    To change user signup, see UserSignupForm and UserSocialSignupForm.
    """
    first_name = forms.CharField(required=False)
    last_name = forms.CharField(required=False)

    class Meta(admin_forms.UserCreationForm.Meta):  # type: ignore[name-defined]
        model = User
        fields = ("email","first_name", "last_name", "role", "password1", "password2")
        field_classes = {"email": EmailField}
        error_messages = {
            "email": {"unique": _("This email has already been taken.")},
        }
    
class UserSignupForm(SignupForm):
    """
    Form that will be rendered on a user sign up section/screen.
    Default fields will be added automatically.
    Check UserSocialSignupForm for accounts created from social.
    """


class UserSocialSignupForm(SocialSignupForm):
    """
    Renders the form when user has signed up using social accounts.
    Default fields will be added automatically.
    See UserSignupForm otherwise.
    """
The admin.py file has the following code:
from allauth.account.decorators import secure_admin_login
from django.conf import settings
from django.contrib import admin
#from django.contrib.auth import admin as auth_admin
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin

from .forms import UserAdminChangeForm
from .forms import UserAdminCreationForm
from .models import User

if settings.DJANGO_ADMIN_FORCE_ALLAUTH:
    # Force the `admin` sign in process to go through the `django-allauth` workflow:
    # https://docs.allauth.org/en/latest/common/admin.html#admin
    admin.autodiscover()
    admin.site.login = secure_admin_login(admin.site.login)  # type: ignore[method-assign]


@admin.register(User)
class UserAdmin(BaseUserAdmin):
    form = UserAdminChangeForm
    add_form = UserAdminCreationForm
    fieldsets = (
        (None, {"fields": ("email", "role", "password")}),
        (
            _("Personal info"),
            {
                "fields": (
                    "first_name",
                    "last_name",
                ),
            },
        ),
        (
            _("Permissions"),
            {
                "fields": (
                    "is_active",
                    "is_staff",
                    "is_superuser",
                    "groups",
                    "user_permissions",
                ),
            },
        ),
        (_("Important dates"), {"fields": ("last_login", "date_joined")}),
    )
    list_display = ["email", "first_name", "last_name", "role"]
    search_fields = [
        "first_name",
        "last_name",
        "email"
    ]
    list_editable = ["role"]
    list_filter = ["role"]
    ordering = ["id"]
    add_fieldsets = (
        (
            None,
            {
                "classes": ("wide",),
                "fields": ("email", "role", "password1", "password2", "first_name", "last_name"),
            },
        ),
    )

当我运行 python manage.py createsuperuser 时,我只得到填写电子邮件、password1 和验证密码的字段,但随后出现错误 CommandError: This field can be Blank.;该字段不能为空。;该字段不能为空。;该字段不能为空。我什至不知道错误涉及哪个字段。有线索吗?

django django-admin django-custom-user
1个回答
0
投票

未知部分除外

  • 设置.DJANGO_ADMIN_FORCE_ALLAUTH
  • 从 rhs_soccer.users.enums 导入 UserRoles

你的源代码,我用同样的代码测试没有问题。

模型.py

class User(AbstractBaseUser, PermissionsMixin):
    PLAYER = 'PR'
    COACH = 'CO'
    MANAGER = 'MG'
    PARENT = 'PR'
    ADMIN = 'AM'
    ROLES = [
      (PLAYER, 'PLAYER'),
      (COACH, 'COACH'),
      (MANAGER, 'MANAGER'),
      (PARENT, 'PARENT'),
      (ADMIN, 'ADMIN')
    ]
    ...
        role = CharField(
        _("Role"),
        max_length=50,
        choices=ROLES,
        default=PLAYER,
    )
    ...

forms.py

admin.autodiscover()
admin.site.login = secure_admin_login(admin.site.login)  # type: ignore[method-assign]

有问题的createsuperuser命令的实际调用对应的是这个文件中的handle方法。

发问者的错误消息似乎与用户模型的 REQUIRED_FIELDS 值有关,但发问者的 REQUIRED_FIELDS 为空。 所以请尝试调试这部分

for field_name in self.UserModel.REQUIRED_FIELDS:
    field = self.UserModel._meta.get_field(field_name)
    user_data[field_name] = options[field_name]
    if user_data[field_name] is not None:
        user_data[field_name] = field.clean(user_data[field_name], None)
    while user_data[field_name] is None:
        message = self._get_input_message(field)
        input_value = self.get_input_data(field, message)
        user_data[field_name] = input_value
        if field.many_to_many and input_value:
            if not input_value.strip():
                user_data[field_name] = None
                self.stderr.write("Error: This field cannot be blank.")
                continue
            user_data[field_name] = [pk.strip() for pk in input_value.split(",")]

    if not field.many_to_many:
        fake_user_data[field_name] = user_data[field_name]
        # Wrap any foreign keys in fake model instances.
        if field.many_to_one:
            fake_user_data[field_name] = field.remote_field.model(user_data[field_name])

这方面似乎有问题。 我想尝试更多调试,但我的代码没有发生错误。 如果调试这部分没有解决问题,请将内容settings.py附在问题正文中。

© www.soinside.com 2019 - 2024. All rights reserved.