首页 > 解决方案 > 将 Dj-Rest-Auth 注册与没有用户名字段的自定义用户模型一起使用时出现 FieldDoesNotExist 错误

问题描述

我有一个自定义用户模型,它使用电子邮件登录并且没有用户名字段。我正在尝试使用dj-rest-auth进行基于休息的用户注册和登录。

我在我的 settings.py 中放置了以下内容:

SITE_ID = 1
AUTH_USER_MODEL = "users.User"
ACCOUNT_EMAIL_VERIFICATION = "none"
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_USERNAME_REQUIRED = False

AUTHENTICATION_BACKENDS = (
    "django.contrib.auth.backends.ModelBackend",
    "allauth.account.auth_backends.AuthenticationBackend",
)

REST_AUTH_REGISTER_SERIALIZERS = {
    'REGISTER_SERIALIZER': 'users.serializers.CustomRegisterSerializer',
}

当尝试通过注册端点注册时,执行甚至永远不会到达我的自定义注册序列化程序,因为它会引发错误

Exception in thread django-main-thread:
Traceback (most recent call last):
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/site-packages/django/db/models/options.py", line 581, in get_field
    return self.fields_map[field_name]
KeyError: 'username'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/threading.py", line 926, in _bootstrap_inner
    self.run()
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/site-packages/django/utils/autoreload.py", line 53, in wrapper
    fn(*args, **kwargs)
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/site-packages/django/core/management/commands/runserver.py", line 117, in inner_run
    self.check(display_num_errors=True)
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/site-packages/django/core/management/base.py", line 395, in check
    include_deployment_checks=include_deployment_checks,
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/site-packages/django/core/management/base.py", line 382, in _run_checks
    return checks.run_checks(**kwargs)
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/site-packages/django/core/checks/registry.py", line 72, in run_checks
    new_errors = check(app_configs=app_configs)
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/site-packages/django/core/checks/urls.py", line 13, in check_url_config
    return check_resolver(resolver)
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/site-packages/django/core/checks/urls.py", line 23, in check_resolver
    return check_method()
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/site-packages/django/urls/resolvers.py", line 407, in check
    for pattern in self.url_patterns:
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/site-packages/django/utils/functional.py", line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/site-packages/django/urls/resolvers.py", line 588, in url_patterns
    patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/site-packages/django/utils/functional.py", line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/site-packages/django/urls/resolvers.py", line 581, in urlconf_module
    return import_module(self.urlconf_name)
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 728, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/Users/torsten/journal/journal/urls.py", line 26, in <module>
    url(r'^rest-auth/registration/', include('rest_auth.registration.urls'))
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/site-packages/django/urls/conf.py", line 34, in include
    urlconf_module = import_module(urlconf_module)
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 728, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/site-packages/rest_auth/registration/urls.py", line 4, in <module>
    from .views import RegisterView, VerifyEmailView
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/site-packages/rest_auth/registration/views.py", line 26, in <module>
    from rest_auth.registration.serializers import (VerifyEmailSerializer,
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/site-packages/rest_auth/registration/serializers.py", line 166, in <module>
    class RegisterSerializer(serializers.Serializer):
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/site-packages/rest_auth/registration/serializers.py", line 168, in RegisterSerializer
    max_length=get_username_max_length(),
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/site-packages/allauth/utils.py", line 63, in get_username_max_length
    max_length = User._meta.get_field(USER_MODEL_USERNAME_FIELD).max_length
  File "/Users/torsten/opt/anaconda3/envs/journal/lib/python3.7/site-packages/django/db/models/options.py", line 583, in get_field
    raise FieldDoesNotExist("%s has no field named '%s'" % (self.object_name, field_name))
django.core.exceptions.FieldDoesNotExist: User has no field named 'username'

有趣的是,如果我只是删除/site-packages/dj_rest_auth/registration/serializers.py那句话中的行

username = serializers.CharField(
    max_length=get_username_max_length(),
    min_length=allauth_settings.USERNAME_MIN_LENGTH,
    required=allauth_settings.USERNAME_REQUIRED
)

注册运行完美无缺,并达到了它拿起我的自定义序列化程序并让我毫无问题地注册新用户的地步。但是像这样直接篡改包文件似乎是一个非常糟糕的解决方案。

有谁知道如何在不编辑 dj_rest_auth 包的源代码的情况下摆脱上述错误?

编辑:这是我的自定义注册序列化程序的代码:

class CustomRegisterSerializer(serializers.Serializer):
    email = serializers.EmailField(required=True)
    password1 = serializers.CharField(write_only=True)
    password2 = serializers.CharField(write_only=True)

    def get_cleaned_data(self):
        return {
            "password": self.validated_data.get("password1", ""),
            "email": self.validated_data.get("email", ""),
        }

    def save(self, request):
        self.cleaned_data = self.get_cleaned_data()
        user = User(**self.cleaned_data)
        user.save()
        return user

标签: djangodjango-rest-frameworkdjango-rest-auth

解决方案


所以我想知道为什么导入其他 4 个序列化程序会触发错误然后发现它:

class RegisterSerializer(serializers.Serializer):
    username = serializers.CharField(
        max_length=get_username_max_length(),
        min_length=allauth_settings.USERNAME_MIN_LENGTH,
        required=allauth_settings.USERNAME_REQUIRED
    )

该函数get_username_max_length()在声明时调用,它调用导入用户模型并从字段中获取最大长度的 allauth 实用程序方法。

您的解决方法是在设置ACCOUNT_USER_MODEL_USERNAME_FIELDNone设置为,以便它只返回 0 而不会尝试从用户模型中获取用户名字段。


推荐阅读