djangopython-3.xdjango-rest-framework

Register User with custom fields in Djoser and Rest Framework


I'm trying to use the "register" endpoint from Djoser. It works properly, but I need more fields than just "username", "email" and "password". I've seen this question and indeed I can see the fields I wanted (in the browsable API). But when I try to post it, I get this error

ImproperlyConfigured at /account/register/ Could not resolve URL for hyperlinked relationship using view name "user-detail". You may have failed to include the related model in your API, or incorrectly configured the lookup_field attribute on this field.

And I don't have idea what's going wrong.

My models.py looks so:

from django.db import models


class User(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    email = models.CharField(max_length=100, blank=False)
    name = models.CharField(max_length=100, blank=False)
    last_name = models.CharField(max_length=100, blank=False)
    birthday = models.CharField(max_length=15, blank=False)
    password = models.CharField(max_length=100, blank=False)

    class Meta:
        ordering = ('created',)

the serializers.py

from rest_framework import serializers
from users.models import User


class UserSerializer(serializers.HyperlinkedModelSerializer):

    class Meta:
        model = User
        fields = ('url', 'id', 'email', 'name', 'last_name', 'birthday', 'password')

my views.py

from users.models import User
from users.serializers import UserSerializer
from rest_framework import viewsets


class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

and in the settings.py I added:

DJOSER = {
    ...
    'SERIALIZERS': {
        'user_registration': 'users.serializers.UserSerializer',
    },
}

EDIT

App/urls.py

from django.conf.urls import url, include
from users import views
from rest_framework.routers import DefaultRouter
from rest_framework.schemas import get_schema_view

# Create a router and register our viewsets with it.
router = DefaultRouter()
router.register(r'users', views.UserViewSet)

schema_view = get_schema_view(title='Pastebin API')

# The API URLs are now determined automatically by the router.
# Additionally, we include the login URLs for the browsable API.

urlpatterns = [
    url(r'^', include(router.urls)),
    url('^schema/$', schema_view),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]

api/urls.py

from django.conf.urls import url, include
from django.contrib import admin
from rest_framework_jwt import views as jwt_views
from rest_framework import routers

router = routers.DefaultRouter()

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^', include(router.urls)),
    url(r'^account/', include('djoser.urls')),
    url(r'^auth/login/', jwt_views.obtain_jwt_token, name='auth'),
]

Does someone have an idea?


Solution

  • The exception is clear: Django cannot resolve URL by user-detail name. It tries to do so because you've made an extended serializer from serializers.HyperlinkedModelSerializer with a url field, which should contain a link to your specific user object.

    The problem I see is that your main urls.py does not include api urls, and they all duplicated and wired up kinda strange. I would rewrite it as follows (assuming you also have user app):

    Root urls.py:

    from django.conf.urls import url, include
    from django.contrib import admin
    
    from rest_framework.schemas import get_schema_view
    from rest_framework_jwt import views as jwt_views
    
    schema_view = get_schema_view(title='Pastebin API')
    
    urlpatterns = [
        url('^schema/$', schema_view),
        url(r'^admin/', admin.site.urls),
        url(r'^user/', include('user.urls')),
        url(r'^account/', include('djoser.urls')),
        # Not sure if you need both:
        url(r'^auth/login/', jwt_views.obtain_jwt_token, name='auth'),
        url(
            r'^api-auth/',
            include('rest_framework.urls', namespace='rest_framework')),
    ]
    

    User app urls.py:

    from django.conf.urls import url, include
    from rest_framework.routers import DefaultRouter
    
    from .views import UserViewSet
    
    router = DefaultRouter()
    router.register(r'users', UserViewSet)
    
    urlpatterns = [
        url(r'^', include(router.urls)),
    ]
    

    And I'm not sure why you need another app called api though.

    If it doesn't help, try examining this article on namespacing the router.