I have to create an API for an existing Django based web app and I'm using DRF to do so. Although I've never used DRF before, everything was incredibly clear and fine until I ran into this problem. Here's the URL in question:
http://www.<customer-website-name>.com/api/friendship-requests/<sender-pk>/
According to the requirements spec that I was given, it's supposed to be handled like this:
- [GET] Return a
FriendshipRequestobject that was sent to the currently authenticated user by a user whosepk = <sender-pk>or 404 if such request doesn't exist. - [PUT] Accepts an
AcceptRejectobject (e.g., JSON{"accepted": false}). Ifaccepted == True, clean upFriendshipRequest, create a newFriendshipobject, return 201; ifaccepted == False, markFriendshipRequestas rejected, return 204
Here's the AcceptReject class and it's serializer:
class AcceptReject(object):
def __init__(self, accepted):
self.accepted = accepted
class AcceptRejectSerializer(serializers.Serializer):
accepted = serializers.BooleanField()
This is the view I'm using to handle the url:
class FriendshipRequestDetail(mixins.RetrieveModelMixin,
generics.GenericAPIView):
def get_serializer_class(self):
if self.request.method == 'PUT':
return serializers.AcceptRejectSerializer
return serializers.FriendshipRequestSerializer
def get_object(self):
sender = generics.get_object_or_404(get_user_model(),
pk=self.kwargs['pk'])
obj = generics.get_object_or_404(FriendshipRequest,
from_user=sender,
to_user=self.request.user)
self.check_object_permissions(self.request, obj)
return obj
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return Response(status=status.HTTP_204_NO_CONTENT)
I naively thought that overriding get_serializer_class() to return a serializer based on request method would be enough, but it wasn't.
Also, as you can see, I haven't even started writing the PUT handler. Just it's presence is enough to cause the following error when I try to use the browsable api:
Environment:
Request Method: GET
Request URL: http://127.0.0.1:8000/api/friendship-requests/5/
Django Version: 1.8.4
Python Version: 3.4.3
Installed Applications:
('django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.gis',
'rest_framework',
'rest_framework.authtoken',
'friendship',
'REDACTED.REDACTED')
Installed Middleware:
('django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware')
Traceback:
File "/home/manvis/REDACTED/env/lib/python3.4/site-packages/django/core/handlers/base.py" in get_response
164. response = response.render()
File "/home/manvis/REDACTED/env/lib/python3.4/site-packages/django/template/response.py" in render
158. self.content = self.rendered_content
File "/home/manvis/REDACTED/env/lib/python3.4/site-packages/rest_framework/response.py" in rendered_content
71. ret = renderer.render(self.data, media_type, context)
File "/home/manvis/REDACTED/env/lib/python3.4/site-packages/rest_framework/renderers.py" in render
669. context = self.get_context(data, accepted_media_type, renderer_context)
File "/home/manvis/REDACTED/env/lib/python3.4/site-packages/rest_framework/renderers.py" in get_context
614. raw_data_put_form = self.get_raw_data_form(data, view, 'PUT', request)
File "/home/manvis/REDACTED/env/lib/python3.4/site-packages/rest_framework/renderers.py" in get_raw_data_form
561. content = renderer.render(serializer.data, accepted, context)
File "/home/manvis/REDACTED/env/lib/python3.4/site-packages/rest_framework/serializers.py" in data
487. ret = super(Serializer, self).data
File "/home/manvis/REDACTED/env/lib/python3.4/site-packages/rest_framework/serializers.py" in data
223. self._data = self.to_representation(self.instance)
File "/home/manvis/REDACTED/env/lib/python3.4/site-packages/rest_framework/serializers.py" in to_representation
447. attribute = field.get_attribute(instance)
File "/home/manvis/REDACTED/env/lib/python3.4/site-packages/rest_framework/fields.py" in get_attribute
418. raise type(exc)(msg)
Exception Type: AttributeError at /api/friendship-requests/5/
Exception Value: Got AttributeError when attempting to get a value for field `accepted` on serializer `AcceptRejectSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `FriendshipRequest` instance.
Original exception text was: 'FriendshipRequest' object has no attribute 'accepted'.
Like I've said, it's my first time using DRF, but, if I understood the trace correctly, it seems that the error stems from DRF trying to render the form for the browsable api, unfortunately, I can't go without it, because a browsable api is also a requirement.
What else do I need to change/override in order to get browsable api working for this view?