Register User with custom fields in Djoser and Rest Framework - django

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?

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.

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.

Related

Converting to using URL router is causing a ImproperlyConfigured exception

I have been working through the Django Rest Framework tutorial and on the very last step I am encountering the error:
Exception Type: ImproperlyConfigured.
Exception Value:
Could not resolve URL for hyperlinked relationship using view name "snippet-detail". You may have failed to include the related model in your API, or incorrectly configured the lookup_field attribute on this field.
When trying to view either /settings/ or /users/ (visiting any user pages yields the same exception but with "user-detail" in place of "snippet-detail") as well as any specific indices of them, etc. All that works is root and login.
All my code thus far has been working fine and I'm very confused as to why copy-pasting from the tutorial would yield such catastrophic results
In comparing my snippets files with those available on the tutorial's repo I have not been able to find any significant difference (all that I've found is inconsistencies in whitespace). That being said, here is the code I'm using.
snippets/views.py:
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer, UserSerializer
from rest_framework import generics, permissions
from django.contrib.auth.models import User
from snippets.permissions import IsOwnerOrReadOnly
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse
from rest_framework import renderers
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import permissions
from rest_framework import viewsets
class UserViewSet(viewsets.ReadOnlyModelViewSet):
"""
This viewset automatically provides `list` and `retrieve` actions.
"""
queryset = User.objects.all()
serializer_class = UserSerializer
class SnippetViewSet(viewsets.ModelViewSet):
"""
This viewset automatically provides `list`, `create`, `retrieve`,
`update` and `destroy` actions.
Additionally we also provide an extra `highlight` action.
"""
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly,
IsOwnerOrReadOnly]
#action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer])
def highlight(self, request, *args, **kwargs):
snippet = self.get_object()
return Response(snippet.highlighted)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
snippets/urls.py:
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from snippets import views
# Create a router and register our viewsets with it.
router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet,basename="snippets")
router.register(r'users', views.UserViewSet,basename="users")
# The API URLs are now determined automatically by the router.
urlpatterns = [
path('', include(router.urls)),
]
snippets/serializers.py:
from django.contrib.auth.models import User
from rest_framework import serializers
from snippets.models import Snippet
class SnippetSerializer(serializers.HyperlinkedModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
highlight = serializers.HyperlinkedIdentityField(
view_name='snippet-highlight', format='html')
class Meta:
model = Snippet
fields = ('url', 'id', 'highlight', 'owner', 'title', 'code',
'linenos', 'language', 'style')
class UserSerializer(serializers.HyperlinkedModelSerializer):
snippets = serializers.HyperlinkedRelatedField(
many=True, view_name='snippet-detail', read_only=True)
class Meta:
model = User
fields = ('url', 'id', 'username', 'snippets')
tutorial/urls.py:
"""tutorial URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('snippets.urls')),
]
urlpatterns += [
path('api-auth/', include('rest_framework.urls')),
]
Router was being passed the wrong base names (plural forms of snippet and user rather than singular). Thanks to #IainShelvington for the answer in the comments!
To elaborate:
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from snippets import views
# Create a router and register our viewsets with it.
router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet,basename="snippets")
router.register(r'users', views.UserViewSet,basename="users")
# The API URLs are now determined automatically by the router.
urlpatterns = [
path('', include(router.urls)),
]
should have been
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from snippets import views
# Create a router and register our viewsets with it.
router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet,basename="snippet")
router.register(r'users', views.UserViewSet,basename="user")
# The API URLs are now determined automatically by the router.
urlpatterns = [
path('', include(router.urls)),
]

Dynamic reverse URL name supplied from model Django

I'm trying to reverse(just the way reverse_lazy works) the url_name stored in the SubMenu.link
Here is my code
My Model
class SubMenu(models.Model):
menu = models.ForeignKey(MainMenu, on_delete=models.CASCADE, related_name="submenus")
title = models.CharField(max_length=50)
link = models.CharField(max_length=50, null=True, default="null")
def __str__(self):
return self.title
My root urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('bodys.urls')),
path('blog', include('blogs.urls')),
path('contact', include('contacts.urls')),
path('services/', include('services.urls')),
]

Django Rest Framework AttributeError: 'str' object has no attribute 'get_default_basename'

This is my first time using viewsets and routers. When I run the server, it shows the that error.
Here is the view (inside a file called api.py):
class LeadViewset(viewsets.ModelViewSet):
queryset = Lead.objects.all()
permission_classes = [
permissions.AllowAny
]
serializer_class = LeadSerializer
serializer:
class LeadSerializer(serializers.ModelSerializer):
class Meta:
model = Lead
fields = '__all__'
urls:
from rest_framework import routers
from .api import LeadViewset
router = routers.DefaultRouter
router.register('api/leads', LeadViewset, 'leads')
What am I doing wrong?
urlpatterns = router.urls
Modify:
router = routers.DefaultRouter
router.register('api/leads', LeadViewset, 'leads')
To:
router = routers.DefaultRouter()
router.register('api/leads', LeadViewset, basename='leads')
Modify your urls.py like this
from rest_framework.routers import DefaultRouter
from .api import LeadViewSet
router = DefaultRouter()
router.register('api/lead',LeadViewSet,'lead')
urlpatterns = router.urls

How to accommodate APIView & ViewSet views in urls.py

How would one write a urls.py file to accommodate views created from APIView and ViewSet.
entity.views.py
from .models import Entity
from .serializers import EntitySerializer
class EntityViewSet(DefaultsMixin, ListCreateRetrieveUpdateViewSet):
"""
"""
queryset = Entity.objects.all()
serializer_class = EntitySerializer
filter_fields = ('id', 'entity_number')
class PersonProfileList(APIView):
"""
person profile
"""
def get(self, request, format=None):
pass
entity.urls.py
from django.conf.urls import url, include
from rest_framework.routers import DefaultRouter
from rest_framework.urlpatterns import format_suffix_patterns
from . import views
entity_router = DefaultRouter()
entity_router.register(r'entity', views.EntityViewSet)
urlpatterns = [
url(r'profile/$', views.PersonProfileList.as_view(), name='profile_list'), # Is this correct?
url(r'profile/(?P<pk>[0-9]+)/$', views.PersonProfileList.as_view(), name='profile_detail'),
]
urlpatterns = format_suffix_patterns(urlpatterns)
main urls.py
from django.conf.urls import include, url
from django.contrib import admin
from entities.urls import entity_router, urlpatterns
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^entities/', include(entity_router.urls)), #This I know works
url(r'^entities/', include(urlpatterns.url)), # This throws errors
]
What is the best way to accommodate both types of Views in the same URL file and have them appear under one /entity unlike now when am getting two /entity entries. Also, once I get into the /entity page in the browsable API, how do I make the /entity/profile viewable since now it only shows /entity. See images for guide.
Root Page
Entities Page

Django rest framework No module named .serializers

For some reason my serialize module is not being recognized, any ideas why this is? I have installed rest_framework and have it in my settings.py file under apps.
For some reason though my serializer.py file is showing rest_framework import is 'unresolved', not sure why this is or if that is the cause of the problem but I have had that before where my editor seems to sometimes mark imports as unresolved but still work.
Here is my serializes.py
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework import routers, serializers, viewsets, permissions
from .models import Part, Supplier, SupplierPart
class PartSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Part
field = [
'id',
'name',
'code',
]
class SupplierSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Supplier
field = [
'id',
'name',
]
class SupplierPartSerializer(serializers.HyperlinkedModelSerializer):
part = PartSerializer()
supplier = SupplierSerializer()
class Meta:
model = SupplierPart
field = [
'id',
'part',
'supplier',
'supplier_code',
'description',
'price',
'sale_price',
'quantity',
'photo',
'url',
]
class SupplierPartViewSet(viewsets.ModelViewSet):
queryset = SupplierPart.objects.all()
serializer_class = SupplierPartSerializer
Here is my URls:
from django.conf import settings
from django.conf.urls import include, url
from django.contrib import admin
from rest_framework import routers
from SupplierPart.serializers import SupplierPartViewSet
router = routers.DefaultRouter()
router.register(r"SupplierPart", SupplierPartViewSet)
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^search/', include('haystack.urls')),
url(r'^$', include('haystack.urls')),
url(r'^part/', include('products.urls')),
url(r'^api/', include(router.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
I am getting this error though when I try to go to my site
---->>>>>>>>>>>>
use "from rest_framework.serializers import *"
i resolved this error by replace
"from rest_framework import serializers"
with
"from rest_framework.serializers import *"
about the unresolved imports: are you using a virtualenv? if so, be sure your IDE is using it as interpreter.
As I understand from your code, SupplierPart is a model. And you are trying to import serializers from it in your urls.py file.
When, you should import it from the app. For example. if your serializers.py is located in suppliers app (folder/package) then you should import it like this:
from suppliers.serializers import SomeSerializer
P.S.
serializers.py file is supposed to hold Serializers, not ViewSets
If your serializers are in different folder nested somewhere in your app in django and you get this error even though the import seems to be okay,
try to create inside the nested folder empty file and call it __init__.py.
For example:
if I have chat app inside django project and want to seperate my serializers into different folder which I will call serializers it will look like this: