【问题标题】:Creating Custom User Class in Django在 Django 中创建自定义用户类
【发布时间】:2019-03-31 07:20:51
【问题描述】:

我已经阅读并重新阅读了有关此问题的其他问题,但我仍然无法创建自定义 Django 用户模型。我不断收到错误消息:Manager isn't available; 'auth.User' has been swapped for 'Users.User'

如果错误不清楚,我创建了一个Users 应用程序,其中models.py 文件定义了一个自定义用户类User

这是我项目中的相关文件,UserTest

  1. 注册应用,指定自定义用户模型:

UserTest> UserTest> settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'Users'
]

AUTH_USER_MODEL = 'Users.User'
  1. 通过我的 User 模型扩展默认 Django User 类并将其连接到 Profile 模型(与问题不严格相关,但该方法的基本方面。)

UserTest > 用户 > models.py

from django.db import models
from django.contrib.auth.models import AbstractUser


class User(AbstractUser):
    email = models.CharField(max_length=128, blank=False, unique=True, verbose_name='Email', name='email')


class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    ...
  1. 在我的 Users 应用的 admin.py 中注册新的 User 模型(不确定测试快速前端功能是否需要这样做?)

UserTest > 用户 > admin.py

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User

admin.site.register(User, UserAdmin)

我创建了一些基本表单和视图,以允许前端提交相关的用户和个人资料数据。鉴于错误,我认为它们不相关,但如果有人认为它们是相关的,我可以将它们包括在内。同样,错误如下:

Manager isn't available; 'auth.User' has been swapped for 'Users.User'

我最初使用AbstractBaseUser 类创建了一个自定义User 模型,该文档描述了必须创建一个自定义Manager 类。我在使用这种方法时遇到了同样的错误,并且没有读到使用这种方法时需要相同的自定义,依赖于AbstractUser

在我的 UserTest > Users > forms.py 文件中,我尝试通过以下两种方式访问​​我的 Users.models.User 模型:

  1. 直接导入:

from .models import User

  1. 通过使用 Django 的 get_user_model() 函数:

from django.contrib.auth import get_user_model User = get_user_model()

第二种方法似乎已经解决了许多其他问题,例如问题HERE,但对我没有帮助(除非我遗漏了什么)。

错误的完整回溯在这里:

Internal Server Error: /test-form/
Traceback (most recent call last):
  File "C:\Users\...\Desktop\UserTest\venv\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
    response = get_response(request)
  File "C:\Users\...\Desktop\UserTest\venv\lib\site-packages\django\core\handlers\base.py", line 126, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "C:\Users\...\Desktop\UserTest\venv\lib\site-packages\django\core\handlers\base.py", line 124, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\...\Desktop\UserTest\Users\views.py", line 19, in NewUserRegistration
    print("USERFORM:", user_form, type(user_form), dir(user_form))
  File "C:\Users\...\Desktop\UserTest\venv\lib\site-packages\django\utils\html.py", line 397, in <lambda>
    klass.__str__ = lambda self: mark_safe(klass_str(self))
  File "C:\Users\...\Desktop\UserTest\venv\lib\site-packages\django\forms\forms.py", line 142, in __str__
    return self.as_table()
  File "C:\Users\...\Desktop\UserTest\venv\lib\site-packages\django\forms\forms.py", line 284, in as_table
    errors_on_separate_row=False,
  File "C:\Users\...\Desktop\UserTest\venv\lib\site-packages\django\forms\forms.py", line 202, in _html_output
    top_errors = self.non_field_errors()  # Errors that should be displayed above all fields.
  File "C:\Users\...\Desktop\UserTest\venv\lib\site-packages\django\forms\forms.py", line 313, in non_field_errors
    return self.errors.get(NON_FIELD_ERRORS, self.error_class(error_class='nonfield'))
  File "C:\Users\...\Desktop\UserTest\venv\lib\site-packages\django\forms\forms.py", line 180, in errors
    self.full_clean()
  File "C:\Users\...\Desktop\UserTest\venv\lib\site-packages\django\forms\forms.py", line 383, in full_clean
    self._post_clean()
  File "C:\Users\...\Desktop\UserTest\venv\lib\site-packages\django\contrib\auth\forms.py", line 107, in _post_clean
    super()._post_clean()
  File "C:\Users\...\Desktop\UserTest\venv\lib\site-packages\django\forms\models.py", line 403, in _post_clean
    self.instance.full_clean(exclude=exclude, validate_unique=False)
  File "C:\Users\...\Desktop\UserTest\venv\lib\site-packages\django\db\models\base.py", line 1137, in full_clean
    self.clean()
  File "C:\Users\...\Desktop\UserTest\venv\lib\site-packages\django\contrib\auth\models.py", line 338, in clean
    self.email = self.__class__.objects.normalize_email(self.email)
  File "C:\Users\...\Desktop\UserTest\venv\lib\site-packages\django\db\models\manager.py", line 188, in __get__
    cls._meta.swapped,
AttributeError: Manager isn't available; 'auth.User' has been swapped for 'Users.User'
[26/Oct/2018 09:47:02] "POST /test-form/ HTTP/1.1" 500 118088

感谢您的帮助。通常,如果我能够在 SO 上输入整篇文章而没有“啊哈”的时刻,我知道我很糟糕。

更新 1:添加 forms.pyviews.py

在我的UserTest &gt; Users 应用中,views.pyforms.py 如下:

UserTest > 用户 > forms.py

from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.core.exceptions import ValidationError

from django.contrib.auth import get_user_model
User = get_user_model()


class NewUser(UserCreationForm):
    email = forms.EmailField(max_length=96)
    password = forms.PasswordInput()
    username = forms.CharField(max_length=18)

    def clean_email(self):
        email = self.cleaned_data['email'].lower()
        r = User.objects.filter(email=email)
        if r.count():
            raise ValidationError("Email already exists")
        return email

    def save(self, commit=True):

        user = User.objects.create_user(
            self.cleaned_data['email'],
            self.cleaned_data['password'],
            self.cleaned_data['username']
        )
        return user

注意:这里我尝试了get_user_model() 方法以及从Users.models 导入我的自定义User 类,但都没有解决错误。

UserTest > 用户 > views.py

from django.shortcuts import render
from django.contrib import messages
from .forms import NewUser


def NewUserRegistration(request):

    if request.method == 'POST':
        user_form = NewUser(request.POST)

        if user_form.is_valid():
            user_form.save()
            messages.success(request, 'Account Created Successfully!')
    else:
        user_form = NewUser()

    return render(request, 'Users/test-form.html', {'user_form': user_form})

【问题讨论】:

  • 回溯显示这发生在您的 NewUserRegistration 视图中。您需要展示该视图及其形式。
  • 我已经更新了答案,详见Update 1

标签: django django-models django-authentication django-users


【解决方案1】:

作为the documentation explains,诸如“UserCreationForm”之类的表单与用户绑定,需要重写或扩展以使用自定义用户模型。

因此,如图所示,您需要重写内部 Meta 类以指向您的模型:

class NewUser(UserCreationForm):
    ...
    class Meta(UserCreationForm.Meta):
        model = get_user_model()

【讨论】:

  • 谢谢,这是导致错误被抛出的问题。
【解决方案2】:

当您使用自定义user model 时,它需要定义其objects,即它的manager,其中包含其各种方法,例如create_usercreate_superuser

您可以使用BaseUserManager 继承您的自定义管理器并在您的User 模型中定义它。

可能是——

class UserManager(BaseUserManager):
    def create_user(self, email, date_of_birth, password=None):
        """
        Creates and saves a User with the given email, date of
        birth and password.
        """
        if not email:
            raise ValueError('Users must have an email address')

        user = self.model(
            email=self.normalize_email(email),
            date_of_birth=date_of_birth,
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, date_of_birth, password):
        """
        Creates and saves a superuser with the given email, date of
        birth and password.
        """
        user = self.create_user(
            email,
            password=password,
            date_of_birth=date_of_birth,
        )
        user.is_admin = True
        user.save(using=self._db)
        return user

class User(AbstractUser):
    email = models.CharField(max_length=128, blank=False, unique=True, verbose_name='Email', name='email')
    objects = UserManager()

这是一个简单的例子,您可以根据需要使用UserManager

建议参考文档以获得更清晰的理解 - https://docs.djangoproject.com/en/2.1/topics/auth/customizing/

【讨论】:

  • 正如我所提到的,我在使用AbstractBaseUser 方法时尝试了该方法,但没有任何区别。我只是在这里添加了相同的方法,并确认仍然会抛出相同的错误。
猜你喜欢
  • 2011-07-04
  • 1970-01-01
  • 2013-11-15
  • 2018-05-21
  • 2014-03-24
  • 1970-01-01
  • 2018-01-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多