I have a custom user model that uses email for login and does not have a username field. I am trying to use dj-rest-auth for rest-based user registration and login.
I placed the following in my 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',
}
When trying to register via the registration endpoint the execution never even reaches my custom registration serializer, as it raises an error
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'
Funny thing is, if I just remove lines in /site-packages/dj_rest_auth/registration/serializers.py
that say
username = serializers.CharField(
max_length=get_username_max_length(),
min_length=allauth_settings.USERNAME_MIN_LENGTH,
required=allauth_settings.USERNAME_REQUIRED
)
the registration runs flawlessly and gets to the point where it picks up my custom serializer and lets me register new users without any problem. But directly tampering with the package files like this does seem like an awfully hacky solution.
Does anybody know how I can get rid of the error above without editing the source code of the dj_rest_auth package?
Edit: Here is the code for my Custom Register Serializer:
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
So I was wondering why the import of the 4 other serializers triggered the error and then spotted it:
The function
get_username_max_length()
is invoked at declaration time, which calls the allauth utility method that imports the user model and gets the max length from the field.Your fix is to set
ACCOUNT_USER_MODEL_USERNAME_FIELD
toNone
in settings, so that it simply returns 0 without trying to get the username field from the user model.