In my Django REST framework project i have this model:
class ml_request(models.Model):
model_id = models.CharField(max_length=100)
created = models.DateTimeField(auto_now=True)
p_country = models.CharField(max_length=100, blank=False, default='')
p_description = models.TextField(null=False, blank=False)
p_designation = models.CharField(max_length=200, blank=False, default='')
p_points = models.IntegerField(default=00)
p_price = models.IntegerField(default=00, blank=False)
p_province = models.CharField(max_length=100, blank=False, default='')
p_region_1 = models.CharField(max_length=100, blank=False, default='')
p_region_2 = models.CharField(max_length=100, blank=False, default='')
p_variety = models.CharField(max_length=100, blank=False, default='')
p_winery = models.CharField(max_length=100, blank=False, default='')
owner = models.ForeignKey('auth.User', related_name='req_owner',
on_delete=models.CASCADE)
highlighted = models.TextField()
class Meta:
ordering = ('created',)
then i create my serializer like this:
from rest_framework import serializers
from botoapi.models import ml_request, ml_response, LANGUAGE_CHOICES,
STYLE_CHOICES, ml_logs
from django.contrib.auth.models import User
class RequestSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.IntegerField(label='ID', read_only=True)
highlight = serializers.HyperlinkedIdentityField(view_name='request-highlight', format='html')
owner = serializers.ReadOnlyField(source='owner.username')
class Meta:
model = ml_request
fields = ('id', 'model_id', 'highlight', 'created', 'p_country',
'p_description', 'p_designation',
'p_points', 'p_price', 'p_province', 'p_region_1', 'p_region_2',
'p_variety', 'p_winery', 'owner')
def create(self, validated_data):
log_save = ml_logs(l_verbose=validated_data, l_method="CREATE",
l_action=validated_data.get("model_id", None))
log_save.save()
return validated_data
and is my view code:
class RequestViewSet(viewsets.ModelViewSet):
queryset = ml_request.objects.all()
serializer_class = RequestSerializer
permission_classes = (IsAuthenticatedOrReadOnly,
IsOwnerOrReadOnly,)
#detail_route(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)
bur when i run it and try to add values django return this error:
AttributeError at /requests/
'dict' object has no attribute 'pk'
Request Method: POST
Request URL: http://127.0.0.1:8000/requests/
Django Version: 1.11.7
Exception Type: AttributeError
Exception Value:
'dict' object has no attribute 'pk'
i have the id as PK and i add it in my serializer, someone can help me to wonder why this happens?
Thanks in advance
From 3.x onwards,
If you want to add django auto 'id' explicitly in HyperlinkedModelSerializer, you need to use ReadOnlyField (not an IntegerField). Or else you can include it in 'fields'.
class RequestSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.ReadOnlyField()
And by default the serializer will include a url field instead of a primary key field. You can explicitly include the primary key by adding it to the fields option.
The name of the URL field defaults to 'url'. You can override this
globally, by using the URL_FIELD_NAME setting.
Related
I'm trying to create a ViewSet for the Course model (to simply display all courses), but I'm getting the following error when trying to access it. I'm new to creating ViewSets and Django in general, what am I doing wrong?
Django 2.2
Error
AttributeError: Got AttributeError when attempting to get a value for field `title` on serializer `CourseSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `QuerySet` instance.
Original exception text was: 'QuerySet' object has no attribute 'title'.
CourseViewSet
class CourseViewSet(viewsets.ModelViewSet):
def list(self, request):
queryset = Course.objects.all()
serializer = CourseSerializer(queryset)
return Response(serializer.data)
CourseSerializer
class CourseSerializer(serializers.ModelSerializer):
class Meta:
model = Course
fields = (
'id',
'title',
'description',
'active',
'individual_result',
'course_duration',
'video',
'manager_id'
)
models/Course
class Course(models.Model):
title = models.CharField(max_length=255, blank=False, null=False)
description = models.CharField(max_length=255, blank=True, null=True)
active = models.BooleanField(default=True)
individual_result = models.BooleanField(default=False)
course_duration = models.CharField(max_length=255, blank=True, null=True)
video = models.CharField(max_length=255, blank=True, null=True)
manager_id = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
def __str__(self):
return self.title
You should serialize with many=True, since a queryset is a collection of objects that can contain zero, one, or more elements:
serializer = CourseSerializer(queryset, many=True)
For more information, see the Dealing with multiple objects section [drf-doc].
I've set up my models, serializers and viewsets in my Django REST API to assign a search record to a particular user, and to associate all the relevant user's searches to their record in the User model. It was all working fine, but I'm now getting the TypeError error message (in the subject line of this question) when I try to create a new user. I've listed the relevant models, serializers and viewsets below. Please could anyone take a look and let me know where I'm going wrong? Any help would be very much appreciated.
User serializer:
class UserSerializer(serializers.ModelSerializer):
searches = serializers.PrimaryKeyRelatedField(many=True, queryset=SearchHistoryModel.objects.all())
class Meta:
model = User
fields = ('id', 'username', 'email', 'password', 'searches')
extra_kwargs = {'email': {
'required': True,
'validators': [UniqueValidator(queryset=User.objects.all())]
}}
def create(self, validated_data):
user = User.objects.create_user(**validated_data)
Token.objects.create(user=user)
return user
User viewset:
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [permissions.AllowAny]
Search model:
class SearchHistoryModel(models.Model):
"""
Stores each user's search submission
"""
created_date = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, related_name='searches', on_delete=models.CASCADE)
cpu_component_name = models.CharField(max_length=10, blank=False)
cpu_subcomponent_name = models.CharField(max_length=50, blank=False)
motherboard_name = models.CharField(max_length=20, blank=False)
gpu_component_name = models.CharField(max_length=10, blank=True, null=True)
gpu_subcomponent_name = models.CharField(max_length=50, blank=True, null=True)
gpu_subcomponent_quantity = models.PositiveIntegerField(default=0)
ram_component_name = models.CharField(max_length=15, blank=True, null=True)
ram_component_quantity = models.PositiveIntegerField(default=0)
ssd_component_name = models.CharField(max_length=15, blank=True, null=True)
ssd_component_quantity = models.PositiveIntegerField(default=0)
hdd_component_name = models.CharField(max_length=20, blank=True, null=True)
hdd_component_quantity = models.PositiveIntegerField(default=0)
optical_drive_name = models.CharField(max_length=15, blank=True, null=True)
class Meta:
verbose_name = 'Search'
verbose_name_plural = 'Searches'
ordering = ['owner', 'created_date']
def __str__(self):
return '{}\'s search choices'.format(self.owner)
Search serializer:
class SearchHistorySerializer(serializers.ModelSerializer):
"""
Serializes the user's search history data passed into the SearchHistoryModel
Associates each search with the relevant user
"""
owner = serializers.ReadOnlyField(source='owner.username')
class Meta:
model = SearchHistoryModel
fields = (
'id', 'created_date', 'owner', 'cpu_component_name', 'cpu_subcomponent_name',
'motherboard_name', 'gpu_component_name', 'gpu_subcomponent_name',
'gpu_subcomponent_quantity', 'ram_component_name', 'ram_component_quantity',
'ssd_component_name', 'ssd_component_quantity', 'hdd_component_name',
'hdd_component_quantity', 'optical_drive_name'
)
Search viewset:
class SearchHistoryViewSet(viewsets.ModelViewSet):
queryset = SearchHistoryModel.objects.all()
serializer_class = SearchHistorySerializer
permission_classes = [permissions.IsAuthenticated]
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
In user = User.objects.create_user(**validated_data), validated_data contains a searches value which is an id.
But actually the ForeignKey is in the other sense : in Searches model, and to refer to a User instance, not the opposite.
To link a user to searches, it is not in User DB table that you write an id, but in Searches that you write a User id.
class UserSerializer(serializers.ModelSerializer):
(...)
def create(self, validated_data):
# Extract the value from 'validated_data'
search_ids = validated_data.pop('searches', None)
user = User.objects.create_user(**validated_data)
Token.objects.create(user=user)
# Update existing search instances
for search_id in search_ids:
Search.objects.filter(id=search_id).update(owner=user)
return user
I am creating rest api using Django Rest Framework. I am using Djanfo 2.0.5 and python 3. I am getting error "Object of type 'type' is not JSON serializable." at the time of submitting form in browser. I tried with POSTMAN and also getting same error. I have attached snaps of my code of model, serializers and view classes.
from django.db import models
# Create your models here.
class User(models.Model):
full_name = models.CharField(max_length=255, blank=False)
email = models.EmailField(blank=False, unique=True)
password = models.CharField(max_length=100, blank=False)
profile_pic = models.FileField()
age = models.CharField(max_length=3, blank=False)
location_lat = models.CharField(max_length=100, blank=False)
location_long = models.CharField(max_length=100, blank=False)
address = models.CharField(max_length=255, blank=False)
experience_level = models.CharField(max_length=50, blank=False)
utr_rating = models.CharField(max_length=50, blank=False)
match_price = models.IntegerField
auth_token = models.CharField(max_length=100, blank=False, unique=True)
fb_token = models.CharField(max_length=100, unique=True)
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
def __str__(self):
return "{}".format(self.full_name)
from rest_framework import serializers
from .models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id',
'full_name',
'email',
'password',
'profile_pic',
'age',
'location_lat',
'location_long',
'address',
'experience_level',
'utr_rating',
'match_price',
'auth_token',
'fb_token',
'date_created',
'date_modified')
read_only_fields = ('date_created', 'date_modified', 'profile_pic')
from rest_framework import generics
from .serializers import UserSerializer
from .models import User
class CreateUser(generics.ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
def perform_create(self, serializer):
serializer.save()
Traceback
This code will work..
class CreateUser(generics.ListCreateAPIView):
serializer_class = UserSerializer
queryset = User.objects.all()
def create(self, request, *args, **kwargs):
serializer = UserSerializer(data=request.data)
if not serializer.is_valid(raise_exception=False):
return Response({"status":"failure","status_message":serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
serializer.save()
return Response({"status":"success","status_message":"User Created Successfully"}, status=status.HTTP_200_OK)
I found a lot of answers to the similar issue, but none of them helped me.
I am new to the backend and Django, I already spent a few days trying figure out what I am doing wrong, but no success.
I would appreciate any help a lot!
So, when I call http://127.0.0.1:8000/users/{user_name}/
I am getting :
ImproperlyConfigured: Could not resolve URL for hyperlinked relationship using view name "post-detail". You may have failed to include the related model in your API, or incorrectly configured the lookup_field attribute on this field.
If I change HyperlinkedRelatedField on any other field it's working properly...
urls.py
app_name = 'api'
urlpatterns = [
url(r'^posts/(?P<post_id>\d+)/$', PostDetails.as_view(),
name='post-detail'),
url(r'^users/(?P<username>[\w\-]+)/$', UserPosts.as_view()),
]
views.py
class PostDetails(APIView):
"""
- GET a post
"""
def get(self, request, post_id):
post = Post.objects.get(id=post_id)
post_serializer = PostSerializer(post)
return Response(post_serializer.data)
class UserPosts(APIView):
"""
GET all user posts
"""
def get(self, request, username):
user = User.objects.get(username=username)
serializer = UserSerializer(user, context={'request': request})
return Response(serializer.data)
serializer.py
class UserSerializer(serializers.ModelSerializer):
posts = serializers.HyperlinkedRelatedField(many=True,
read_only=True,
view_name='post-detail',
lookup_field='id')
# Mandatory for UUID serialization
user_id = serializers.UUIDField()
class Meta:
model = User
exclude = ('id', 'password')
read_only_fields = ('created', 'username', 'posts',)
class PostSerializer(serializers.ModelSerializer):
author = UserSerializer()
class Meta:
model = Post
fields = '__all__'
models.py
class User(models.Model):
username = models.CharField(max_length=30, unique=True)
password = models.CharField(max_length=50)
email = models.EmailField(unique=True)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
phone = models.CharField(max_length=20, blank=False, unique=True)
user_id = models.UUIDField(editable=False,
unique=True,
null=False,
db_index=True,)
created = models.DateTimeField()
id = models.BigAutoField(primary_key=True)
class Meta:
ordering = ('created',)
def __unicode__(self):
return "Email: %s " % self.email
class Post(models.Model):
created = models.DateTimeField()
is_active = models.BooleanField(default=False)
title = models.CharField(max_length=200, blank=False)
body_text = models.CharField(max_length=1000, blank=False)
address = models.CharField(max_length=100)
author = models.ForeignKey(User, on_delete=models.PROTECT,
related_name='posts')
price = models.DecimalField(max_digits=10, decimal_places=0)
id = models.BigAutoField(primary_key=True)
class Meta:
ordering = ('created',)
def __unicode__(self):
return "Title : %s , Author: %s " % (self.title, self.author)
Your lookup_field does not match your url one which is post_id
url(r'^posts/(?P<post_id>\d+)/$', PostDetails.as_view(),
name='post-detail'),
From docs:
lookup_field - The field on the target that should be used for the lookup. Should correspond to a URL keyword argument on the referenced view. Default is 'pk'.
lookup_url_kwarg - The name of the keyword argument defined in the URL conf that corresponds to the lookup field. Defaults to using the same value as lookup_field.
So you should be fine with this:
posts = serializers.HyperlinkedRelatedField(many=True,
read_only=True,
view_name='post-detail',
lookup_url_kwarg='post_id')
I'm having problems with Django Rest Framework reverse function (from rest_framework.reverse import reverse) and django_reverse.
When I try to return the url of a single object, I'm getting all the url pattern, instead of the ID I get the text representation of the model.
For example I have a model called Driver, when I try to get the url of a Driver instance with pk=1, the response is
http : //base_url/driver/driver%20object/.
This can be resolve by overriding Driver unicode function to return str(self.pk), but I don't like this approach.
Also previous versions of django/drf did not present this issue.
First of all my virtual-env is:
Django==1.8.4
django-braces==1.8.0
django-extensions==1.5.5
django-filter==0.10.0
django-oauth-toolkit==0.8.1
djangorestframework==3.3.2
psycopg2==2.6
etc
Models
class Dominio(AuditableModel):
dominio = models.CharField(max_length=200, blank=False, null=False, unique=True)
pais = models.ForeignKey(Pais, null=False, blank=False)
#property
def owners(self):
if self.conductores.count() > 0:
return self.conductores.filter(is_owner=True).all()[0]
else:
return None
class Conductor(AuditableModel):
usuario = models.ForeignKey(User, null=False, blank=False, related_name='dominios')
dominio = models.ForeignKey(Dominio, null=False, blank=False, related_name='conductores')
is_owner = models.BooleanField(default=False, null=False)
#
# def __unicode__(self):
# return str(self.pk)
class Meta:
verbose_name_plural = "conductores"
Serializers
class ConductorSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Conductor
fields = ('id', 'url', 'usuario', 'dominio', 'is_owner')
class DominioSerializer(serializers.HyperlinkedModelSerializer):
owners = serializers.HyperlinkedRelatedField(read_only=True, view_name='conductor-detail')
class Meta:
model = Dominio
fields = ('id', 'url', 'dominio', 'pais', 'owners')
result
"owners": "http : //localhost:8000/ventana/api/v1/conductores/Conductor%20object/"
Django rest framework api response
but, if I change the #property owners method to return a list of drivers (conductores), then the urls are correct
Models
class Dominio(AuditableModel):
dominio = models.CharField(max_length=200, blank=False, null=False, unique=True)
pais = models.ForeignKey(Pais, null=False, blank=False)
#property
def owners(self):
if self.conductores.count() > 0:
return self.conductores.filter(is_owner=True).all()
else:
return []
Serializers
class DominioSerializer(serializers.HyperlinkedModelSerializer):
owners = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='conductor-detail')
class Meta:
model = Dominio
fields = ('id', 'url', 'dominio', 'pais', 'owners')
Result
"owners": [ "http : //localhost:8000/ventana/api/v1/conductores/1/"]
Django rest framework api response 2