Reputation: 3410
I'm using Django==1.10.5
and djangorestframework==3.5.3
.
I have a few ModelViewSet
s that handle JSON API requests properly. Now, I'd like to use TemplateRenderer
to add HTML rendering to those same ModelViewSet
s. I started with the list
endpoint, and created a simple template that lists the available objects. I implemented the get_template_names
to return the template I created.
Accessing that endpoint through the browser works fine when there are no objects to list, so everything related to setting up HTML renderers alongside APIs seems to work.However, when tere are objects to return the same endpoint fails with the following error:
ValueError: dictionary update sequence element #0 has length XX; 2 is required
Where XX
is the number of attributes the object has.
This documentation section suggests the view function should act slightly differently when returning an HTML Response
object, but I assume this is done by DRF's builtin views when necessary, so I don't think that's the issue.
This stackoverflow Q/A also looks relevant but I'm not quite sure it's the right solution to my problem.
How can I make my ModelViewSet
s work with both HTML and JSON renderers?
Thanks!
Upvotes: 5
Views: 2473
Reputation: 8228
DRF has a brief explanation of how to do this in their documentation.
I think you'd do something like this...
On the client side, tell your endpoint what type of response you want:
fetch(yourAPIUrl, {
headers: {
'Accept': 'application/json'
// or 'Accept': 'text/html'
}
})
In your view, just check that and act accordingly:
class FlexibleAPIView(APIView):
"""
API view that can render either JSON or HTML.
"""
renderer_classes = [TemplateHTMLRenderer, JSONRenderer]
def get(self, request, *args, **kwargs):
queryset = Things.objects.all()
# If client wants HTML, give them HTML.
if request.accepted_renderer.format == 'html':
return Response({'things': queryset}, template_name='example.html')
# Otherwise, the client likely wants JSON so serialize the data.
serializer = ThingSerializer(instance=queryset)
data = serializer.data
return Response(data)
Upvotes: 3