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

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

Related

I don't understand that keyerror occurs in my code in django

I am using the django rest framework modelviewset to re-turn the entire post when I request get. But after writing the code, I sent the get request and the following error appears.
Traceback (most recent call last):
File "C:\Users\kurak\AppData\Local\Programs\Python\Python38-32\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "C:\Users\kurak\AppData\Local\Programs\Python\Python38-32\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Users\kurak\AppData\Local\Programs\Python\Python38-32\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\kurak\AppData\Local\Programs\Python\Python38-32\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "C:\Users\kurak\AppData\Local\Programs\Python\Python38-32\lib\site-packages\rest_framework\viewsets.py", line 114, in view
return self.dispatch(request, *args, **kwargs)
File "C:\Users\kurak\AppData\Local\Programs\Python\Python38-32\lib\site-packages\rest_framework\views.py", line 505, in dispatch
response = self.handle_exception(exc)
File "C:\Users\kurak\AppData\Local\Programs\Python\Python38-32\lib\site-packages\rest_framework\views.py", line 465, in handle_exception
self.raise_uncaught_exception(exc)
File "C:\Users\kurak\AppData\Local\Programs\Python\Python38-32\lib\site-packages\rest_framework\views.py", line 476, in raise_uncaught_except
ion
raise exc
File "C:\Users\kurak\AppData\Local\Programs\Python\Python38-32\lib\site-packages\rest_framework\views.py", line 502, in dispatch
response = handler(request, *args, **kwargs)
File "D:\school\대회 및 프로젝트\CoCo\feed\views.py", line 23, in list
'email': serializer.data['author_email'],
KeyError: 'author_email'
I have clearly stated this in the serializer, but I don't understand why a keyerror appears. Can you tell me what the problem is in my code? Here's my code. Thank in advance.
views.py
class CreateReadPostView (ModelViewSet) :
serializer_class = PostSerializer
permission_classes = [IsAuthenticated]
queryset = Post.objects.all()
def perform_create (self, serializer) :
serializer.save(author=self.request.user)
def list (self, request) :
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
data = {
'author': {
'email': serializer.data['author_email'],
'username': serializer.data['author_username'],
'profile': serializer.data['author_profile']
},
'title': serializer.data['title'],
'text': serializer.data['text'],
'images': serializer.data['image'],
'view': serializer.data['view'],
'tag': serializer.data['tag']
}
return Response(data, status=200)
serializers.py
class PostSerializer (serializers.ModelSerializer) :
author_username = serializers.CharField(source='author.username', read_only=True)
author_email = serializers.CharField(source='author.email', read_only=True)
author_profile = serializers.ImageField(source='author.profile', read_only=True, use_url=True)
title = serializers.CharField(allow_null=True)
text = serializers.CharField(allow_null=True)
image = ImageSerializer(many=True, read_only=True)
class Meta:
model = Post
fields = [
'author_username',
'author_email',
'author_profile',
'title',
'text',
'image',
'view'
]
The problem is how you defined your list method. Please use the default list method in the viewset as a reference to define yours.
Specifically, you are initializing the serializer with request.data, when there is no data in the request because it is a GET request. This is only done in the POST/PUT/PATCH requests when you want to serialize the input and create a new object with the data. Instead, you should pass in the queryset that should be serialized for output.There is KeyError because author_email is readonly and you initialized the serializer in write mode so of course, the author-email is not available.
I would advice that you instead keep the inbuilt list method and use a nested representation in the serializers like this:
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = Author
fields = ('username', 'email', 'profile')
class PostSerializer (serializers.ModelSerializer) :
author = AuthorSerializer(read_only=True)
title = serializers.CharField(allow_null=True)
text = serializers.CharField(allow_null=True)
image = ImageSerializer(many=True, read_only=True)
class Meta:
model = Post
fields = [
'author',
'title',
'text',
'image',
'view'
]
Then you can have a simple viewset:
class CreateReadPostView (ModelViewSet) :
serializer_class = PostSerializer
permission_classes = [IsAuthenticated]
queryset = Post.objects.all()
def perform_create (self, serializer) :
serializer.save(author=self.request.user)
To understand more about how the list method is implemented, check the ListMixin. It fetches the queryset, applies filters and then paginates them. These are things you ommitted in your code

How to get a value in a database and display on django form

I have a DuesLevy model with a field called user which happen to be a foreign key to my User model. I want to display email value from the User model to my form AddMemberDuesForm()
The reason is this I want to get the email and amount value and pass it to my payment processor.
I am using class based views to process my form below is my code
forms.py
class AddMemberDuesForm(forms.ModelForm):
class_of_dues = forms.CharField(required=False, widget=forms.Select(choices=options.CLASS_OF_DUES, attrs={'class':'form-control'}))
payment_circle = forms.CharField(required=False, widget=forms.Select(choices=options.PAYMENT_CIRCLE, attrs={'class':'form-control'}))
payment_option = forms.CharField(required=False, widget=forms.Select(choices=options.PAYMENT_OPTION, attrs={'class':'form-control'}))
payment_channel = forms.CharField(required=False, widget=forms.Select(choices=options.PAYMENT_CHANNEL_TYPE, attrs={'class':'form-control'}))
amount = forms.DecimalField(widget=forms.NumberInput(attrs={'class':'form-control'}))
payment_date = forms.DateField(widget=forms.DateInput(attrs={'class':'form-control', 'type':'date'}))
description = forms.CharField(widget=forms.Textarea(attrs={'class':'form-control'}))
class Meta():
model = DuesLevy
exclude = ('date_recorded', 'start_date', 'end_date', 'transaction_id')
views.py
class AddMemberDues(LoginRequiredMixin, CreateView):
login_url = '/backoffice/'
model = DuesLevy
template_name = 'dashboard/add-edit-member-dues.html'
form_class = AddMemberDuesForm
context_object_name = 'member_form'
def post(self, request, *args, **kwargs):
form = AddMemberDuesForm(request.POST)
if form.is_valid():
form = AddMemberDuesForm()
form.user.email = form.user.cleaned_data['email']
self.template_name = 'dashboard/payment.html'
form.save()
return render(request, self.template_name,
{'email': form.cleaned_data['email'], 'amount': form.cleaned_data['amount']})
def get(self, request, *args, **kwargs):
initial = {'email':request.user.email}
form = AddMemberDuesForm(initial=initial)
return render(request, self.template_name, {'email': form.cleaned_data['email']})
I get this error in the
'AddMemberDuesForm' object has no attribute 'cleaned_data'
Internal Server Error: /backoffice/add-member-dues/
Traceback (most recent call last):
File "C:\Users\Benedict\Miniconda3\envs\mycda\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "C:\Users\Benedict\Miniconda3\envs\mycda\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Users\Benedict\Miniconda3\envs\mycda\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\Benedict\Miniconda3\envs\mycda\lib\site-packages\django\views\generic\base.py", line 71, in view
return self.dispatch(request, *args, **kwargs)
File "C:\Users\Benedict\Miniconda3\envs\mycda\lib\site-packages\django\contrib\auth\mixins.py", line 52, in dispatch
return super().dispatch(request, *args, **kwargs)
File "C:\Users\Benedict\Miniconda3\envs\mycda\lib\site-packages\django\views\generic\base.py", line 97, in dispatch
return handler(request, *args, **kwargs)
File "D:\mycda\backend\views.py", line 348, in get
return render(request, self.template_name, {'email': form.cleaned_data['email']})
AttributeError: 'AddMemberDuesForm' object has no attribute 'cleaned_data'
It would help to have a look at the code in models.py. Have you got a function get cleaned_data() there?

Django Rest Framework: AttributeError: 'NoneType' object has no attribute '_meta' [for OneToOneField]

I need help with a POST request using Django rest framework.
I have a User model that inherits from AbstractBaseUser which has 2 fields: name and email.
Then I have a DojoMaster model that has a OneToOne relationship with the User model:
class DojoMaster(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
phone = models.BigIntegerField()
country = models.ForeignKey(Country, on_delete=models.CASCADE)
I want to register the dojo master via an API so I created the following serializers:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('name', 'email', 'password')
class DojoMasterCreateSerializer(serializers.ModelSerializer):
user = UserSerializer(required=True)
class Meta:
model = DojoMaster
fields = ('user', 'phone', 'country')
def create(self, validated_data):
validated_data['country'] = Country.objects.get(
country=validated_data['country'])
user_data = validated_data.pop('user')
user = UserSerializer.create(UserSerializer(), validated_data=user_data)
subscriber, created = DojoMaster.objects.update_or_create(user=user,
phone = validated_data.pop('phone'),
country = validated_data['country'])
return subscriber
To call on these serializers, I created the following view:
class DojoMasterCreateView(generics.CreateAPIView):
def post(self, request, format='json'):
serializer = DojoMasterCreateSerializer(data=request.data)
if serializer.is_valid(raise_exception=ValueError):
serializer.create(validated_data=request.data)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
For the body of the POST request I had the following:
{
"user": {
"name": "XYZ",
"email": "xyz#mail.com",
"password": "8Xa,9Lv&"
},
"phone": 9696510,
"country": "USA"
}
However, when I do that I get the following error:
Traceback (most recent call last):
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\django\core\handlers\exception.py", line 41, in inner
response = get_response(request)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\django\core\handlers\base.py", line 187, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\django\core\handlers\base.py", line 185, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\django\views\decorators\csrf.py", line 58, in wrapped_view
return view_func(*args, **kwargs)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\django\views\generic\base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\views.py", line 494, in dispatch
response = self.handle_exception(exc)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\views.py", line 454, in handle_exception
self.raise_uncaught_exception(exc)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\views.py", line 491, in dispatch
response = handler(request, *args, **kwargs)
File "C:\Users\app_dev\development\GOQ\dojomaster_api\views.py", line 29, in post
if serializer.is_valid(raise_exception=ValueError):
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\serializers.py", line 236, in is_valid
self._validated_data = self.run_validation(self.initial_data)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\serializers.py", line 435, in run_validation
value = self.to_internal_value(data)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\serializers.py", line 465, in to_internal_value
validated_value = field.run_validation(primitive_value)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\serializers.py", line 437, in run_validation
self.run_validators(value)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\fields.py", line 533, in run_validators
for validator in self.validators:
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\fields.py", line 392, in validators
self._validators = self.get_validators()
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\serializers.py", line 1460, in get_validators
self.get_unique_for_date_validators()
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\serializers.py", line 1502, in get_unique_for_date_validators
info = model_meta.get_field_info(self.Meta.model)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\utils\model_meta.py", line 39, in get_field_info
forward_relations = _get_forward_relationships(opts)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\utils\model_meta.py", line 96, in _get_forward_relationships
not field.remote_field.through._meta.auto_created
AttributeError: 'NoneType' object has no attribute '_meta'
I cannot figure out what the problem is. Help would be much appreciated.
serializer.is_valid method accepts keyword argument raise_exception. And its value should be true or false. By default it is false. If it is true, the exception will be auto triggered.
change your serializer.is_valid(raise_exception=ValueError) to serializer.is_valid().
And also for saving the serializer you should call the save method not the create method
class DojoMasterCreateView(generics.CreateAPIView):
def post(self, request, format='json'):
serializer = DojoMasterCreateSerializer(data=request.data)
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)
or in simple form
class DojoMasterCreateView(generics.CreateAPIView):
def post(self, request, format='json'):
serializer = DojoMasterCreateSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
And i have no idea what user = UserSerializer.create(UserSerializer(), validated_data=user_data) means or create method logic is doing. If you want to save the user data, then follow the code given beloe
class DojoMasterCreateSerializer(serializers.ModelSerializer):
user = UserSerializer(required=True)
class Meta:
model = DojoMaster
fields = ('user', 'phone', 'country')
def create(self, validated_data):
user_data = validated_data.pop('user')
user = User.objects.create(**user_data)
subscriber, created = DojoMaster.objects.update_or_create(user=user, **validated_data)
return subscriber
And the json should contain the id of the country, like
{
"user": {
"name": "XYZ",
"email": "xyz#mail.com",
"password": "8Xa,9Lv&"
},
"phone": 9696510,
"country": 1
}

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

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'

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