DRF Serializer - Many to Many with through field, Object has no attribute - python

I have models with many-to-many relationships with a through model. I am trying to set up a DRF serializer to display this data, but I am getting an error message whenever I try to render the API.
# models.py - simplified
class Person(models.Model):
first_name = models.CharField(max_length=250)
last_name = models.CharField(max_length=250)
status = models.IntegerField(choices=STATUS_CHOICES)
village = models.ForeignKey(Village)
gender = models.IntegerField(choices=GENDER_CHOICES)
class Case(models.Model):
summary = models.TextField()
session = models.ForeignKey(Session, on_delete=models.CASCADE)
case_type = models.ForeignKey(CaseType)
court_type = models.IntegerField(choices=COURT_TYPES)
verdict = models.ForeignKey(Verdict)
litigants = models.ManyToManyField(Person, through='Litigant', related_name='litigants')
class Litigant(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
case = models.ForeignKey(Case, on_delete=models.CASCADE)
role = models.ForeignKey(Role)
fine = models.ForeignKey(Money, null=True, related_name='fine')
My serializers.py looks as such:
# serializers.py - simplified
class LitigantSerializer(FlexFieldsModelSerializer):
class Meta:
model = Litigant
fields = ('id', 'person', 'case', 'role', 'fine')
class CaseSerializer(FlexFieldsModelSerializer):
litigants = LitigantSerializer(many=True, read_only=True)
class Meta:
model = Case
fields = ('id', 'summary', 'session', 'case_type', 'court_type', 'verdict', 'litigants')
class PersonSerializer(FlexFieldsModelSerializer):
class Meta:
model = Person
fields = ('id','first_name', 'last_name', 'village', 'status', 'gender')
My views.py is:
# views.py - simplified.
class PersonViewSet(FlexFieldsModelViewSet):
queryset = Person.objects.all().order_by('village__name', 'last_name', 'first_name')
serializer_class = PersonSerializer
class CaseViewSet(FlexFieldsModelViewSet):
queryset = Case.objects.all().order_by('session__village__name', 'session__date', 'court_type')
serializer_class = CaseSerializer
class LitigantViewSet(FlexFieldsModelViewSet):
queryset = Litigant.objects.all().order_by('case__session__village__name', 'case__session__date', 'person__last_name',
'person__first_name')
serializer_class = LitigantSerializer
However, when I navigate to api/cases/ I receive the following error:
'Person' object has no attribute 'person'
I'm not sure why it is using 'person' as an identifier for the Person object, instead of its PK. Is there something I am missing here?
Here is the stack trace, as requested.
Traceback:
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/django/core/handlers/exception.py" in inner
41. response = get_response(request)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/django/core/handlers/base.py" in _get_response
187. response = self.process_exception_by_middleware(e, request)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/django/core/handlers/base.py" in _get_response
185. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/django/views/decorators/csrf.py" in wrapped_view
58. return view_func(*args, **kwargs)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_framework/viewsets.py" in view
90. return self.dispatch(request, *args, **kwargs)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_framework/views.py" in dispatch
489. response = self.handle_exception(exc)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_framework/views.py" in handle_exception
449. self.raise_uncaught_exception(exc)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_framework/views.py" in dispatch
486. response = handler(request, *args, **kwargs)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_flex_fields/views.py" in list
28. return super(FlexFieldsMixin, self).list(request, *args, **kwargs)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_framework/mixins.py" in list
45. return self.get_paginated_response(serializer.data)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_framework/serializers.py" in data
739. ret = super(ListSerializer, self).data
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_framework/serializers.py" in data
263. self._data = self.to_representation(self.instance)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_framework/serializers.py" in to_representation
657. self.child.to_representation(item) for item in iterable
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_framework/serializers.py" in <listcomp>
657. self.child.to_representation(item) for item in iterable
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_framework/serializers.py" in to_representation
501. ret[field.field_name] = field.to_representation(attribute)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_framework/serializers.py" in to_representation
657. self.child.to_representation(item) for item in iterable
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_framework/serializers.py" in <listcomp>
657. self.child.to_representation(item) for item in iterable
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_framework/serializers.py" in to_representation
488. attribute = field.get_attribute(instance)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_framework/relations.py" in get_attribute
179. return get_attribute(instance, self.source_attrs)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_framework/fields.py" in get_attribute
103. instance = getattr(instance, attr)
Exception Type: AttributeError at /api/cases/
Exception Value: 'Person' object has no attribute 'person'

Related

'Request' object has no attribute 'pop' in Django Rest Framework?

I have a Post model which has Foreign key with User model. So when I created Post object I need to pass user instance by overriding the create method inside ModelViewSet but it failed.
here is what I have tried:
models.py
class Post(models.Model):
author = models.ForeignKey(User, related_name="posts", on_delete=models.CASCADE)
title = models.CharField(max_length=200)
content = models.TextField()
serializers.py
class PostSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name="api:posts-detail")
author = UserSerializer()
class Meta:
model = models.Post
fields = ['url', 'id', 'author', 'title', 'content']
views.py
class PostViewSet(viewsets.ModelViewSet):
serializer_class = serializers.PostSerializer
def get_queryset(self, *args, **kwargs):
user = self.request.user
return models.Post.objects.all().filter(author=user)
permission_classes_by_action = {
'create': [permissions.IsAuthenticated],
'list': [permissions.IsAuthenticated],
# other permissions..
}
def create(self, validated_data):
author = validated_data.pop('author_id')
print(author)
post = models.Post.objects.create(author=author, **validated_data)
return post
def list(self, request, *args, **kwargs):
return super(PostViewSet, self).list(request, *args, **kwargs)
# other methods
def get_permissions(self):
try:
# return permission_classes depending on `action`
return [permission() for permission in self.permission_classes_by_action[self.action]]
except KeyError:
# action is not set return default permission_classes
return [permission() for permission in self.permission_classes]
the whole error I got
Traceback (most recent call last):
File "/Users/muongkimhong/Developments/django-api/env/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/Users/muongkimhong/Developments/django-api/env/lib/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/Users/muongkimhong/Developments/django-api/env/lib/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/muongkimhong/Developments/django-api/env/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/Users/muongkimhong/Developments/django-api/env/lib/python3.8/site-packages/rest_framework/viewsets.py", line 125, in view
return self.dispatch(request, *args, **kwargs)
File "/Users/muongkimhong/Developments/django-api/env/lib/python3.8/site-packages/rest_framework/views.py", line 509, in dispatch
response = self.handle_exception(exc)
File "/Users/muongkimhong/Developments/django-api/env/lib/python3.8/site-packages/rest_framework/views.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "/Users/muongkimhong/Developments/django-api/env/lib/python3.8/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
raise exc
File "/Users/muongkimhong/Developments/django-api/env/lib/python3.8/site-packages/rest_framework/views.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
File "/Users/muongkimhong/Developments/django-api/new_api/api/views.py", line 76, in create
author = validated_data.pop('author_id')
File "/Users/muongkimhong/Developments/django-api/env/lib/python3.8/site-packages/rest_framework/request.py", line 418, in __getattr__
return self.__getattribute__(attr)
AttributeError: 'Request' object has no attribute 'pop'
[29/Sep/2020 09:50:36] "POST /api/posts/ HTTP/1.1" 500 103017
I can provide more if you need more information. The error came from the create method inside ModelViewSet.
Thanks
You are mixing up method of ModelViewSet.create with ModelSerializer.create. You need to put it in serializer like this:
class PostSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name="api:posts-detail")
author = UserSerializer(read_only=True)
class Meta:
model = models.Post
fields = ['url', 'id', 'author', 'title', 'content']
def create(self, validated_data):
author = self.context['request'].user
post = models.Post.objects.create(author=author, **validated_data)
return post

Django rest framework's StringRelatedField is throwing KeyError

I have the following model classes.
class Categories(models.Model):
id = models.UUIDField(primary_key=True, auto_created=True, default=uuid.uuid4, unique=True)
business = models.ForeignKey(Business, related_name='category_business', on_delete=models.CASCADE)
name = models.CharField(max_length=128)
class Meta:
unique_together = ('business', 'name')
class Menu(models.Model):
id = models.UUIDField(primary_key=True, auto_created=True, default=uuid.uuid4, unique=True)
business = models.ForeignKey(Business, related_name='menu_business', on_delete=models.CASCADE)
name = models.CharField(max_length=128)
description = models.CharField(max_length=128)
category = models.ForeignKey(Categories, related_name='menus', on_delete=models.CASCADE)
price = models.IntegerField()
class Meta:
unique_together = ('business', 'name', 'category')
def __str__(self):
return '%s %s %s' % (self.name, self.price, self.description)
and I have imported these classes as following as they are located in a separate package
Categories = apps.get_model('business', 'Categories')
Menu = apps.get_model('business', 'Menu')
and this is my serializer class
class GetCategoriesSerializer(serializers.ModelSerializer):
menus = serializers.StringRelatedField(many=True)
class Meta:
model = Categories
fields = ('name', 'menus')
and views is
class GetCategories(generics.ListAPIView):
"""
Returns a list of businesses to the user. It'd read only and no authentication is needed
"""
permission_classes = [ReadOnly]
queryset = Categories.objects.values()
serializer_class = GetCategoriesSerializer
and url has the following
path('customer/<str:pk>/categories', GetCategories.as_view()),
I am getting the following error
Traceback (most recent call last):
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/django/views/generic/base.py", line 71, in view
return self.dispatch(request, *args, **kwargs)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/views.py", line 505, in dispatch
response = self.handle_exception(exc)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/views.py", line 465, in handle_exception
self.raise_uncaught_exception(exc)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/views.py", line 476, in raise_uncaught_exception
raise exc
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/views.py", line 502, in dispatch
response = handler(request, *args, **kwargs)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/generics.py", line 199, in get
return self.list(request, *args, **kwargs)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/mixins.py", line 48, in list
return Response(serializer.data)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/serializers.py", line 760, in data
ret = super().data
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/serializers.py", line 260, in data
self._data = self.to_representation(self.instance)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/serializers.py", line 678, in to_representation
self.child.to_representation(item) for item in iterable
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/serializers.py", line 678, in <listcomp>
self.child.to_representation(item) for item in iterable
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/serializers.py", line 516, in to_representation
attribute = field.get_attribute(instance)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/relations.py", line 529, in get_attribute
relationship = get_attribute(instance, self.source_attrs)
File "/Users/mymac/myapp/mytestapp/venv/lib/python3.7/site-packages/rest_framework/fields.py", line 92, in get_attribute
instance = instance[attr]
Exception Type: KeyError at /customer/85f44d20-f936-4940-8e15-01393e42c4a8/categories
Exception Value: 'menus'
I looked into the DRF example and this seems to be a simple thing to achieve.
https://www.django-rest-framework.org/api-guide/relations/#api-reference
But I am kind of stuck at this point. Am I doing anything wrong? Thanks in advance for any help.
You should've used the QuerySet instead of ValueQuerySet. That is use queryset = Categories.objects.all() instead of queryset = Categories.objects.values()
So change the queryset attribute of the view as,
class GetCategories(generics.ListAPIView):
permission_classes = [ReadOnly]
queryset = Categories.objects.all()
serializer_class = GetCategoriesSerializer

Django "TypeError: '...' object is not iterable"

I need multiple values to be in the courses' contacts, for example, phone, Facebook, etc.
I'm overriding create a method to make writable nested fields. Everything works fine with "branches". I'm confused because I can't get why Contact is not iterable.
Models.py:
class Branch(models.Model):
latitude = models.CharField(max_length=50)
longitude = models.CharField(max_length=50)
address = models.CharField(max_length=100)
class Meta:
ordering = ['latitude']
def __str__(self):
return self.address
class Contact(models.Model):
type = models.IntegerField(choices=TYPE, default=1)
value = models.CharField(max_length=100, null=False)
class Meta:
ordering = ['type']
def __str__(self):
return "{} {}".format(self.type, self.value)
class Course(models.Model):
...
branches = models.ForeignKey(Branch, on_delete=models.CASCADE, null=False, default=True)
contacts = models.ForeignKey(Contact, on_delete=models.CASCADE, null=False, default=True)
class Meta:
ordering = ['name']
def __str__(self):
return self.name
Serializers.py:
class CourseSerializer(serializers.ModelSerializer):
...
branches = BranchSerializer(many=True)
contacts = ContactSerializer(many=True)
class Meta:
model = Course
fields = ['name', 'description', 'category', 'logo', 'contacts', 'branches']
def create(self, validated_data):
branches_data = validated_data.pop('branches')
contacts_data = validated_data.pop('contacts')
course = Course.objects.create(**validated_data)
for branches in branches_data:
branch = Branch.objects.create(**branches)
course.branches = branch
for contacts in contacts_data:
contact = Contact.objects.create(**contacts)
course.contacts = contact
return course
UPD: Traceback:
File "/courseapp_task/venv/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
34. response = get_response(request)
File "/courseapp_task/venv/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
115. response = self.process_exception_by_middleware(e, request)
File "/courseapp_task/venv/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
113. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/courseapp_task/venv/lib/python3.6/site-packages/django/views/decorators/csrf.py" in wrapped_view
54. return view_func(*args, **kwargs)
File "/courseapp_task/venv/lib/python3.6/site-packages/rest_framework/viewsets.py" in view
114. return self.dispatch(request, *args, **kwargs)
File "/courseapp_task/venv/lib/python3.6/site-packages/rest_framework/views.py" in dispatch
505. response = self.handle_exception(exc)
File "/courseapp_task/venv/lib/python3.6/site-packages/rest_framework/views.py" in handle_exception
465. self.raise_uncaught_exception(exc)
File "/courseapp_task/venv/lib/python3.6/site-packages/rest_framework/views.py" in raise_uncaught_exception
476. raise exc
File "/courseapp_task/venv/lib/python3.6/site-packages/rest_framework/views.py" in dispatch
502. response = handler(request, *args, **kwargs)
File "/courseapp_task/venv/lib/python3.6/site-packages/rest_framework/mixins.py" in create
20. headers = self.get_success_headers(serializer.data)
File "/courseapp_task/venv/lib/python3.6/site-packages/rest_framework/serializers.py" in data
559. ret = super().data
File "/courseapp_task/venv/lib/python3.6/site-packages/rest_framework/serializers.py" in data
261. self._data = self.to_representation(self.instance)
File "/courseapp_task/venv/lib/python3.6/site-packages/rest_framework/serializers.py" in to_representation
526. ret[field.field_name] = field.to_representation(attribute)
File "/courseapp_task/venv/lib/python3.6/site-packages/rest_framework/serializers.py" in to_representation
675. self.child.to_representation(item) for item in iterable
The problem is not in your nested serializers. The problem is in your models themselves.
A ForeignKey is a many to one relationship. The way you have defined things, a Course can only have one branch and one contact. Calling the fields "branches" and "contacts" doesn't change that, and neither does setting "many=True" in the serializers.
You need to change the models so that the ForeignKeys are on Branch and Contact themselves, pointing at Course. The serializer would then use the related names.
Note, you shouldn't need to define create; everything there should just work.

How to get just one field from a reverse reference in Django Rest Framework

I have two models, Roundtrip and Tour, and another model called RoundtripTour where I can link those two models in a many-to-many fashion. I have made a rest service that returns a Tour instance and a list of all RoundtripTour instances through a reverse reference, and it works perfectly, but the service returns all fields from the RoundtripTour model, and I want to return only the field that references the Roundtrip model instance.
These are my models:
class Roundtrip(models.Model):
name = models.CharField(max_length=70, verbose_name=_('Name'))
code = models.CharField(max_length=8, verbose_name=_('Code'))
duration = models.IntegerField(verbose_name=_('Duration'))
description = models.TextField(verbose_name=_('Description'))
class Tour(models.Model):
name = models.CharField(max_length=70, verbose_name=_('Name'))
description = models.TextField(verbose_name=_('Description'))
is_own = models.BooleanField(default=True, verbose_name=_('Is own tour?'))
code = models.CharField(max_length=10, verbose_name=_('Code'))
class RoundtripTour(models.Model):
roundtrip = models.ForeignKey(Roundtrip, on_delete=models.PROTECT, related_name='tours', verbose_name=_('Roundtrip'))
tour = models.ForeignKey(Tour, on_delete=models.PROTECT, related_name='roundtrips', verbose_name=_('Tour'))
day = models.IntegerField(verbose_name=_('Day'))
This is my serializer:
class TourRoundtripsSerializer(serializers.HyperlinkedModelSerializer):
roundtrips = serializers.SerializerMethodField()
def get_roundtrips(self, instance):
queryset = [x.roundtrip for x in instance.roundtrips.all()]
return RoundtripSerializer(queryset, many=True, context=self.context).data
class Meta:
model = models.Tour
fields = ('id', 'name', 'description', 'is_own', 'code', 'roundtrips')
This is my view:
class TourRoundtripsViewSet(viewsets.ModelViewSet):
queryset = models.Tour.objects.all()
serializer_class = serializers.TourRoundtripsSerializer
I would like the roundtrips reverser reference to return only the field roundtrip from the RoundtripTour model (roundtrip field of RoundtripTour model). Is that possible?
I made the changes suggested by #Ykh, but I get an error. This is the traceback:
Internal Server Error: /es/reservations_manager/roundtrips/1/composition
Traceback (most recent call last):
File "/Users/hugovillalobos/Documents/Code/IntellibookProject/IntellibookVenv/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
response = get_response(request)
File "/Users/hugovillalobos/Documents/Code/IntellibookProject/IntellibookVenv/lib/python3.6/site-packages/django/core/handlers/base.py", line 128, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/Users/hugovillalobos/Documents/Code/IntellibookProject/IntellibookVenv/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/hugovillalobos/Documents/Code/IntellibookProject/IntellibookVenv/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/Users/hugovillalobos/Documents/Code/IntellibookProject/IntellibookVenv/lib/python3.6/site-packages/rest_framework/viewsets.py", line 103, in view
return self.dispatch(request, *args, **kwargs)
File "/Users/hugovillalobos/Documents/Code/IntellibookProject/IntellibookVenv/lib/python3.6/site-packages/rest_framework/views.py", line 483, in dispatch
response = self.handle_exception(exc)
File "/Users/hugovillalobos/Documents/Code/IntellibookProject/IntellibookVenv/lib/python3.6/site-packages/rest_framework/views.py", line 443, in handle_exception
self.raise_uncaught_exception(exc)
File "/Users/hugovillalobos/Documents/Code/IntellibookProject/IntellibookVenv/lib/python3.6/site-packages/rest_framework/views.py", line 480, in dispatch
response = handler(request, *args, **kwargs)
File "/Users/hugovillalobos/Documents/Code/IntellibookProject/IntellibookVenv/lib/python3.6/site-packages/rest_framework/mixins.py", line 58, in retrieve
return Response(serializer.data)
File "/Users/hugovillalobos/Documents/Code/IntellibookProject/IntellibookVenv/lib/python3.6/site-packages/rest_framework/serializers.py", line 560, in data
ret = super(Serializer, self).data
File "/Users/hugovillalobos/Documents/Code/IntellibookProject/IntellibookVenv/lib/python3.6/site-packages/rest_framework/serializers.py", line 262, in data
self._data = self.to_representation(self.instance)
File "/Users/hugovillalobos/Documents/Code/IntellibookProject/IntellibookVenv/lib/python3.6/site-packages/rest_framework/serializers.py", line 527, in to_representation
ret[field.field_name] = field.to_representation(attribute)
File "/Users/hugovillalobos/Documents/Code/IntellibookProject/IntellibookVenv/lib/python3.6/site-packages/rest_framework/fields.py", line 1855, in to_representation
return method(value)
File "/Users/hugovillalobos/Documents/Code/IntellibookProject/Intellibook/ReservationsManagerApp/serializers.py", line 191, in get_hotels
return HotelSerializer(queryset, many=True).data
File "/Users/hugovillalobos/Documents/Code/IntellibookProject/IntellibookVenv/lib/python3.6/site-packages/rest_framework/serializers.py", line 765, in data
ret = super(ListSerializer, self).data
File "/Users/hugovillalobos/Documents/Code/IntellibookProject/IntellibookVenv/lib/python3.6/site-packages/rest_framework/serializers.py", line 262, in data
self._data = self.to_representation(self.instance)
File "/Users/hugovillalobos/Documents/Code/IntellibookProject/IntellibookVenv/lib/python3.6/site-packages/rest_framework/serializers.py", line 683, in to_representation
self.child.to_representation(item) for item in iterable
File "/Users/hugovillalobos/Documents/Code/IntellibookProject/IntellibookVenv/lib/python3.6/site-packages/rest_framework/serializers.py", line 683, in <listcomp>
self.child.to_representation(item) for item in iterable
File "/Users/hugovillalobos/Documents/Code/IntellibookProject/IntellibookVenv/lib/python3.6/site-packages/rest_framework/serializers.py", line 527, in to_representation
ret[field.field_name] = field.to_representation(attribute)
File "/Users/hugovillalobos/Documents/Code/IntellibookProject/IntellibookVenv/lib/python3.6/site-packages/rest_framework/relations.py", line 356, in to_representation
"the serializer." % self.__class__.__name__
AssertionError: `HyperlinkedRelatedField` requires the request in the serializer context. Add `context={'request': request}` when instantiating the serializer.
[24/May/2018 14:23:52] "GET /es/reservations_manager/roundtrips/1/composition HTTP/1.1" 500 145268
class TourRoundtripsSerializer(serializers.HyperlinkedModelSerializer):
roundtrips = serializers.SerializerMethodField()
def get_roundtrips(self, instance):
queryset = [x.roundtrip for x in instance.roundtrips.all()]
return RoundtripSerializer(queryset, many=True, context=self.context).data
class Meta:
model = models.Tour
fields = ('id', 'name', 'description', 'is_own', 'code', 'roundtrips')
depth = 1
use SerializerMethodField to get whatever you want.

Django Rest Framework not working with simple nested serializer

I was converting my existing app to api based. The structure of my file is as follow:
models.py
class BookDetail(models.Model):
title= models.CharField(max_length=10, default='title')
author= models.CharField(max_length=10)
series= models.CharField(max_length=10)
edition= models.CharField(max_length=10)
description= models.CharField(max_length=10)
keywords= models.CharField(max_length=10)
reading_age= models.CharField(max_length=10)
genre= models.CharField(max_length=10)
publishing_rights= models.CharField(max_length=10)
def __str__(self):
return self.title
class Addon(models.Model):
header= models.CharField(max_length=10)
footer= models.CharField(max_length=10, default='1')
additional_features = models.ForeignKey(BookDetail, related_name='additional_features',
on_delete=models.CASCADE, null=True)
def __str__(self):
return self.header
views.py
class BookDetailsList(APIView):
def get(self, request):
stocks = BookDetail.objects.all()
serializers = BookDetailsSerializer(stocks, many=True)
return Response(serializers.data)
def post(self, request):
serializer = BookDetailsSerializer(data=request.data)
print(serializer.is_valid())
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializer.py
class AddonSerializer(serializers.ModelSerializer):
class Meta:
model = Addon
fields = ('header', 'footer')
class BookDetailsSerializer(serializers.ModelSerializer):
additional_features = AddonSerializer(many=True)
class Meta:
model = BookDetail
fields = ('title', 'author','series', 'edition',
'description', 'keywords', 'reading_age',
'genre', 'publishing_rights','additional_features')
# fields = '__all__'
def create(self, validated_data):
additional_feature = validated_data.pop('additional_features')
book_detail = BookDetail.objects.create(**validated_data)
for a in additional_feature:
Addon.objects.create(additional_features=book_detail, **a)
# Addon.objects.create(additional_features=book_detail, **additional_feature)
return book_detail
My input data is in JSON format
{
"title": "lolwa",
"author": "asd",
"series": "string",
"edition": "a",
"description": "as",
"keywords": "sd",
"reading_age": "aasd",
"genre": "adasda",
"publishing_rights": "aadasd",
"additional_features": [{"header":"head",
"footer":"foot"}]
}
This is working fine. But what I really want is not passing my additional_features as a list which I'm currently doing, I want to pass it like this.
"additional_features": {"header":"head",
"footer":"foot"}
But my code throws error when I'm trying to pass it like this. I made the following changes in my serializer.py
class BookDetailsSerializer(serializers.ModelSerializer):
additional_features = AddonSerializer(many=False)
# additional_features = AddonSerializer(many=True)
class Meta:
model = BookDetail
fields = ('title', 'author','series', 'edition',
'description', 'keywords', 'reading_age',
'genre', 'publishing_rights','additional_features')
# fields = '__all__'
def create(self, validated_data):
additional_feature = validated_data.pop('additional_features')
book_detail = BookDetail.objects.create(**validated_data)
# for a in additional_feature:
# Addon.objects.create(additional_features=book_detail, **a)
Addon.objects.create(additional_features=book_detail, **additional_feature)
return book_detail
Made many=False and removed the for loop. Since both of them, **a and **additional_feature are
OrderedDict([('header', 'head'), ('footer', 'foot')])
I don't see a reason why it is failing.
This is the stack trace of the error
Internal Server Error: /bookdetails/
Traceback (most recent call last):
File "/Users/argo/Django/pagination-backend/env/lib/python3.5/site-packages/rest_framework/fields.py", line 444, in get_attribute
return get_attribute(instance, self.source_attrs)
File "/Users/argo/Django/pagination-backend/env/lib/python3.5/site-packages/rest_framework/fields.py", line 103, in get_attribute
instance = getattr(instance, attr)
AttributeError: 'RelatedManager' object has no attribute 'header'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/argo/Django/pagination-backend/env/lib/python3.5/site-packages/django/core/handlers/base.py", line 149, in get_response
response = self.process_exception_by_middleware(e, request)
File "/Users/argo/Django/pagination-backend/env/lib/python3.5/site-packages/django/core/handlers/base.py", line 147, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/argo/Django/pagination-backend/env/lib/python3.5/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
return view_func(*args, **kwargs)
File "/Users/argo/Django/pagination-backend/env/lib/python3.5/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/Users/argo/Django/pagination-backend/env/lib/python3.5/site-packages/rest_framework/views.py", line 483, in dispatch
response = self.handle_exception(exc)
File "/Users/argo/Django/pagination-backend/env/lib/python3.5/site-packages/rest_framework/views.py", line 443, in handle_exception
self.raise_uncaught_exception(exc)
File "/Users/argo/Django/pagination-backend/env/lib/python3.5/site-packages/rest_framework/views.py", line 480, in dispatch
response = handler(request, *args, **kwargs)
File "/Users/argo/Django/pagination-backend/backend/publishbook/views.py", line 21, in post
return Response(serializer.data, status=status.HTTP_201_CREATED)
File "/Users/argo/Django/pagination-backend/env/lib/python3.5/site-packages/rest_framework/serializers.py", line 531, in data
ret = super(Serializer, self).data
File "/Users/argo/Django/pagination-backend/env/lib/python3.5/site-packages/rest_framework/serializers.py", line 262, in data
self._data = self.to_representation(self.instance)
File "/Users/argo/Django/pagination-backend/env/lib/python3.5/site-packages/rest_framework/serializers.py", line 500, in to_representation
ret[field.field_name] = field.to_representation(attribute)
File "/Users/argo/Django/pagination-backend/env/lib/python3.5/site-packages/rest_framework/serializers.py", line 487, in to_representation
attribute = field.get_attribute(instance)
File "/Users/argo/Django/pagination-backend/env/lib/python3.5/site-packages/rest_framework/fields.py", line 463, in get_attribute
raise type(exc)(msg)
AttributeError: Got AttributeError when attempting to get a value for field `header` on serializer `AddonSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `RelatedManager` instance.
Original exception text was: 'RelatedManager' object has no attribute 'header'.
From the structure of your models, a BookDetail object can have more than one Addon instances, since, Addon model have a foreign key to BookDetail.
If you want to have more than one Addons for a particular BookDetail, you cant update the Addon instance without using a list.
But, if its not the case, then I would recommend using a OneToOne relation instead of Foreign Key.
Actually, its pretty ugly using a OneToOne field, rather you can just add the fields into your parent model(BookDetail), which can be defaulted to null, if there is None.

Categories

Resources