I try to create a new user (django user) via POST with
serializers.py
from rest_framework import serializers
from .models import *
from django.contrib.auth.models import User
class UsuarioSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('email',
'password')
views.py:
class Registrar(mixins.CreateModelMixin, viewsets.GenericViewSet):
serializer_class = UsuarioSerializer
urls.py:
from django.urls import path, include
from . import views
from rest_framework import routers
router = routers.DefaultRouter()
router.register('usuarios', views.UsuarioViewSet)
router.register('tecnicos', views.TecnicoViewSet)
router.register('pedidos', views.PedidoViewSet)
router.register('mispedidos', views.PedidoMiUsuarioSet)
router.register('registrar', views.Registrar, base_name = 'registro')
urlpatterns = [
path('', include(router.urls))
]
When i make a post i get this error:
UNIQUE constraint failed: auth_user.username
This works if i change the model User to Usuario...
Models.py:
class Usuario(models.Model):
email = models.EmailField(max_length=70, blank=True, null=True, unique=True)
password = models.TextField()
def __str__(self):
return self.email
But i need to use the User model from django
The username field in the user model is required.
This is why you must use this field in create operations.
Email address is not mandatory by default.
It happens on Django create user via a unique user username.
Related
I have two models: the first is named Card and has a foreign key (named owner) to the second model (User). I'm trying to write a view that lists all the Cards owned by a User, the client selects the User by changing the URL (not query parameters).
For example, if I make a GET request to /cards/by-user-id/42/, I should get all the Cards owned by the User whose id is 42.
From what I understood, it is possible to achieve this by using an URL pattern like this : path('cards/by-user-id/<int:user_id>', my_view.as_view()) and then in the viewset I can use self.kwargs['user_id'] to get the id and then filter the data. However, I can't find how to do it using routers (more appropriated for djangorestframework). I tried with <int:user_id> in the prefix but it does not pick it up, it just considers it as a normal string, so not only the URL is incorrect (I have to type literally /cards/by-user-id/<int:user_id>/) but also kwargs doesn't contain 'user_id'.
Here is what I tried:
models.py:
from django.contrib.auth.models import User
from django.db import models
class Card(models.Model):
owner = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
serializers.py:
from rest_framework import serializers
from . import models
class CardSerializer(serializers.ModelSerializer):
owner = serializers.StringRelatedField()
class Meta:
model = models.Card
fields = ['owner', 'id']
views.py:
from rest_framework import viewsets
from . import models, serializers
class ListCardsPerUser(viewsets.ModelViewSet):
serializer_class = serializers.CardListSerializer
def get_queryset(self):
models.CardList.objects.filter(owner__id=self.kwargs['user_id'])
urls.py:
from django.urls import path, include
from rest_framework import routers
from . import views
router = routers.SimpleRouter()
router.register(r'cards/by-user-id/<int:user_id>/', views.ListCardsPerUser, basename='cards_list')
urlpatterns = [
path('', include(router.urls)),
]
I'm starting to wonder if it is even possible with routers...
Django version: 4.1 and DRF: 3.14
you should just edit your user serializer
class CardASerializer(serializers.ModelSerializer):
class Meta:
model = Card
fields = "__all__"
class UserSerializer(serializers.ModelSerializer):
cards = CardASerializer(many=True)
class Meta:
model = User
fields = "__all__"
Note that the cards is related_name
class Card(models.Model):
owner = models.ForeignKey(User, null=True,related_name="cards", on_delete=models.SET_NULL)
This question seems to be asked before but none of the answers I came across solve my issue.
I'm getting the following error when I try running the server with python manage.py runserver:
django.core.exceptions.ImproperlyConfigured: The included URLconf 'tutorial.urls' does not appear to have any patterns in it. If you see valid patterns in the file then the issue is probably caused by a circular import.
The error goes away if I change models.py so that my Item class does not extend models.Model.
These are the relevant files:
models.py
from django.db import models
from django.contrib.auth.models import User
class Item(models.Model):
name = models.CharField(max_length=255)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
price = models.DecimalField(decimal_places=2)
def __str__(self):
return self.name
serializers.py
from rest_framework import serializers
from django.contrib.auth.models import User, Group
from .models import Item
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'username', 'email', 'groups')
class GroupSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Group
fields = ('url', 'name')
class ItemSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Item
fields = ('url', 'name', 'owner', 'price')
views.py
from django.contrib.auth.models import User, Group
from rest_framework import viewsets
from .serializers import UserSerializer, GroupSerializer, ItemSerializer
from .models import Item
class UserViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = User.objects.all().order_by('-date_joined')
serializer_class = UserSerializer
class GroupViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows groups to be viewed or edited.
"""
queryset = Group.objects.all()
serializer_class = GroupSerializer
class ItemViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows items to be viewed or edited.
"""
queryset = Item.objects.all()
serializer_class = ItemSerializer
urls.py
from django.urls import include, path
from rest_framework import routers
from tutorial.quickstart import views
router = routers.DefaultRouter()
router.register('users', views.UserViewSet)
router.register('groups', views.GroupViewSet)
router.register('items', views.ItemViewSet)
urlpatterns = [
path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
Overview
I'm setting up a new Django application with Django REST Framework (DRF), and this is my first time using the HyperlinkedModelSerializer for the API endpoint.
I've overridden the get_queryset() method on the ModelViewSet, so I've also the basename argument to the application router and explicitly defined the url attribute in the serializer as suggested here. This fixed issues that I was having with the model's own url attribute.
However, I'm getting the following error message when trying to serialize a ForeignKey field of the same class as the parent model. It fails with the following message:
Could not resolve URL for hyperlinked relationship using view name "employee-detail". You may have failed to include the related model in your API, or incorrectly configured the lookup_field attribute on this field.
Is there something special in the serializer I need to do to support using recursive model relationships like this?
Example code
# app/models.py
from django.db import models
class AbstractBase(models.Model):
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class Employee(AbstractBase):
name = models.CharField(max_length=254)
manager = models.ForeignKey('self', related_name='direct_reports',
on_delete=models.SET_NULL, blank=True, null=True)
...
def __str__(self):
return str(self.name)
# app/views.py
from rest_framework import viewsets
from rest_framework.pagination import PageNumberPagination
from app import models
from app import serializers
# pagination defaults
class StandardResultsSetPagination(PageNumberPagination):
page_size = 25
page_size_query_param = 'page_size'
max_page_size = 1000
class EmployeeViewSet(viewsets.ModelViewSet):
pagination_class = StandardResultsSetPagination
serializer_class = serializers.EmployeeSerializer
http_method_names = ['options', 'get']
def get_queryset(self):
params = self.request.query_params
queryset = models.Employee.objects.all()
# apply url query filters...
return queryset
# app/serializers.py
from app import models
from rest_framework import serializers
class EmployeeSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedRelatedField(
read_only=True, view_name='employees-detail')
manager = serializers.HyperlinkedRelatedField(
read_only=True, view_name='employees-detail')
class Meta:
model = models.Employee
fields = ('url', 'name', 'manager')
# project/urls.py
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/', include('app.urls')),
]
# app/urls.py
from django.conf.urls import url, include
from rest_framework import routers
from app import views
router = routers.DefaultRouter(trailing_slash=False)
router.register(r'employees', views.EmployeeViewSet, basename='employees')
urlpatterns = [
url(r'^', include(router.urls)),
]
I have no idea why this worked, but changing the inherited serializer from serializers.HyperlinkedModelSerializer to serializers.ModelSerializer and removing the overridden url fixed things perfectly.
New serializer looks like this:
# app/serializers.py
from app import models
from rest_framework import serializers
class EmployeeSerializer(serializers.ModelSerializer):
manager = serializers.HyperlinkedRelatedField(
read_only=True, view_name='employees-detail')
class Meta:
model = models.Employee
fields = ('url', 'name', 'manager')
I am having my models.py file defined as below:-
from django.db import models
from django.contrib.auth.models import User
class Custom_User(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
mobile = models.CharField(max_length=20)
REGISTRATION_CHOICES = (
('Learner', 'Learner'),
('Trainer', 'Trainer'),
)
primary_registration_type = models.CharField(max_length=15, choices=REGISTRATION_CHOICES)
def __str__(self):
return self.user.email
As you can see that my Custom_User model uses Django's User model as its foreign Key.
For the above model I have defined my serialziers.py file like this:-
from django.contrib.auth.models import User
from rest_framework import serializers
from .models import *
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'username', 'email')
class Custom_UserSerializer(serializers.HyperlinkedModelSerializer):
user = UserSerializer()
class Meta:
model = Custom_User
fields = ('__all__')
Now I am using this serializers in my viewsets like below:-
from django.contrib.auth.models import User
from rest_framework import viewsets
from .serializers import *
class UserViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = User.objects.all()
serializer_class = UserSerializer
class Custom_UserViewSet(viewsets.ModelViewSet):
queryset = Custom_User.objects.all()
serializer_class = Custom_UserSerializer
class TrainerViewSet(viewsets.ModelViewSet):
queryset = Custom_User.objects.filter(primary_registration_type="Trainer")
serializer_class = Custom_UserSerializer
class LearnerViewSet(viewsets.ModelViewSet):
queryset = Custom_User.objects.filter(primary_registration_type="Learner")
serializer_class = Custom_UserSerializer
And Finally inside my urls.py file I register them as below:-
from rest_framework import routers
router = routers.DefaultRouter()
router.register(r'users', api_mailing_list_views.UserViewSet)
router.register(r'custom_users', api_mailing_list_views.Custom_UserViewSet)
router.register(r'trainers', api_mailing_list_views.TrainerViewSet)
router.register(r'learners', api_mailing_list_views.LearnerViewSet)
urlpatterns = [
path('admin/', admin.site.urls),
path('', mailing_list_views.index, name='index'),
path('api/', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
]
As I was expecting the urls list to be like below in my browser:
{
"users": "http://localhost:8080/api/users/",
"custom_users": "http://localhost:8080/api/custom_users/",
"trainers": "http://localhost:8080/api/trainers/",
"learners": "http://localhost:8080/api/learners/"
}
But what i get instead is a list of urls like this:-
{
"users": "http://localhost:8080/api/users/",
"custom_users": "http://localhost:8080/api/trainers/",
"trainers": "http://localhost:8080/api/trainers/",
"learners": "http://localhost:8080/api/trainers/"
}
However I am not getting any errors or if I visit the following url:-
http://localhost:8080/api/learners/
which is not showing up in the urls list I still get the filtered list of learners in JSON format.
Thanks for the help in advance.
you need to provide basename during router register as all of them actually from same custom_user model.
router = routers.DefaultRouter()
router.register(r'users', api_mailing_list_views.UserViewSet, basename='users')
router.register(r'custom_users', api_mailing_list_views.Custom_UserViewSet, basename='custom_user')
router.register(r'trainers', api_mailing_list_views.TrainerViewSet, basename='trainers')
router.register(r'learners', api_mailing_list_views.LearnerViewSet, basename='learners')
Django-rest-framework's router tries to identify the viewset by its model/queryset, since both viewsets use the same model things most likely get mixed up.
From the documentation:
If unset the basename will be automatically generated based on the queryset attribute of the viewset, if it has one. Note that if the viewset does not include a queryset attribute then you must set basename when registering the viewset.
Try providing a basename to the router:
router.register(r'custom_users', api_mailing_list_views.Custom_UserViewSet, basename='custom_users')
router.register(r'trainers', api_mailing_list_views.TrainerViewSet, basename='trainers')
router.register(r'learners', api_mailing_list_views.LearnerViewSet, basename='learners')
i am using djoser's create token end point to login user but i am getting following error.
I have tried google search but could not find any useful answer.
UPDATE
I have customized user model to add an extra field while registering user.
here is my models.py
from django.db import models
from custom_user.models import AbstractEmailUser
class UserProfile(AbstractEmailUser):
account_address = models.CharField(max_length=100, blank=True)
name = models.CharField(max_length=30, blank=True)
and this is my serializer.py
from djoser.serializers import UserCreateSerializer as BaseUserRegistrationSerializer
from rest_framework import serializers
class UserRegistrationSerializer(BaseUserRegistrationSerializer):
advertisements = serializers.HyperlinkedRelatedField(many=True, view_name='advertisement-detail', read_only=True)
class Meta(BaseUserRegistrationSerializer.Meta):
fields = ('id', 'email', 'advertisements', 'name', 'account_address', 'password')
and urls.py
from django.conf.urls import url, include
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
urlpatterns = [
url(r'^account/', include('djoser.urls')),
url(r'^account/', include('djoser.urls.authtoken'))
]