Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 385
Chuck Aguilar Avatar asked Jan 10 '17 22:01

Chuck Aguilar


Video Answer


2 Answers

You can create a Custom User in django 2.0 using djoser by inheriting with AbstractUser, which creates a new user model with respect to your app like this:

from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    FUNCTION = 1
    VIEWER = 2
    TECHNICIAN = 3
    ROLE_CHOICES = (
        (FUNCTION, 'Functional'),
        (VIEWER, 'Viewer'),
        (TECHNICIAN, 'Technician'),
    )
    role = models.PositiveSmallIntegerField(choices=ROLE_CHOICES, null=True, blank=True)
    REQUIRED_FIELDS = ["email", "role"]

and then defined user new User class in settings.py: AUTH_USER_MODEL = 'app_name.User'

Please note that here I have defined my REQUIRED_FIELDS. So when I use the djoser API /me/, it will give me all the required fields.

like image 89
ARKhan Avatar answered Sep 17 '22 04:09

ARKhan


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.

like image 20
Damaged Organic Avatar answered Sep 19 '22 04:09

Damaged Organic