drf custom response to override Response() - django-rest-framework

I'm using DRF and to return response, I used Response() which located at from rest_framework.response import Response
To make custom response, first, I copied all of the source to custom file.
And in my views, I changed Response() to my own file.
But when I running django server and access via web, it through errors.
AssertionError: .accepted_renderer not set on Response
I just copied original Repsonse() and re-use it.
Why it occur errors?
Purpose of custom response is I want to add more argument that something likes cursor for pagination.
As you know that in original Response, takes 6 arguments.
def __init__(self, data=None, status=None,
template_name=None, headers=None,
exception=False, content_type=None):
And return it in def rendered_content(self), line of ret = renderer.render(self.data, accepted_media_type, context)
So my scenario is, add cursor to __init__ and pass through it to renderer.render().
Any problem with my way?
Thanks.

Related

Wagtail - DRF Response() instead of JsonResponse()

I'm using Wagtail as a headless CMS / API, however instead of using the PagesAPIViewSet I've gone the route of overriding the serve() method as described here to fetch pages:
https://docs.wagtail.org/en/stable/reference/contrib/routablepage.html
This has worked great since I can return a JsonResponse. The problem is that (as far as I understand), debug toolbar only works with the standard rest framework Response(), so I'm trying to find a way to return a DRF Response instead.
The error I'm getting is ".accepted_renderer not set on Response"
How would I set the accepted renderer?
This is roughly what I've got:
from rest_framework.response import Response
from wagtail.core.models import Page
class BasePage(Page, RoutablePageMixin):
....
def serve(self, request, *args, **kwargs):
context = self.get_context(request, *args, **kwargs) # Context where I serialize data to JSON etc.
return Response(data=context['data'], status=status.HTTP_200_OK) ##Throws error, with JsonResponse() it works fine.

How can I disable authentication for GET method in django modelviewset?

I have written one router url and modelviewset like below:
**router.register(r'TestViewSet', views.TestViewSet)
**class TestViewSet(viewsets.ModelViewSet): queryset = Test.objects.all() serializer_class = TestSerializer
for this class, I want to disable authentication for GET method.
Pls give some solution
Well to disable authentication only on the GET method of the ModelViewSet, we are required to override the permission class based on the HTTP method.
To achieve this, try following
from rest_framework import permissions
...
class TestViewSet(viewsets.ModelViewSet):
...
def get_permissions(self):
"""Returns the permission based on the type of action"""
if self.action == "list":
return [permissions.AllowAny()]
return [permissions.IsAuthenticated()]
In the above code, we are checking of the action (assuming you want to allow anyone to see the list, and limit who can perform other actions).
So if the action is list (HTTP method GET) it will allow anyone to access otherwise it will check for authentication.
Hope this answers your question.

Django rest framework XLSX renderer + Apiview

I'm setting up an endpoint on my API which should return a XLSX-file. The DRF-docs mention https://github.com/wharton/drf-renderer-xlsx as the main external rendering package, aside from the pandas which also seem to be able to render XLSX.
In their code example they use a ReadOnlyViewset paired with a mixin, but there is no mention of how it's used with APIViews. Still, I would like to use an APIView as shown by this https://harshahegde.dev/rendering-xlsx-files-in-django-rest-framework-ckagk293p00eumks1bf4dlhie
However..
This works great when using CURL or Postman, but when done through a browser I get this error:
'Request' object has no attribute 'accepted_renderer'
From what I understand this is because there is no Accept header set (e.g 'Accept':'application/xlsx')
I fixed this by removing the Mixin from the renderer_classes, so it simply returns a file called "xlsx" but I can't figure out how to set the filename without the mixin. How do I set the filename using an APIView trying to access the URL from a browser?
My view:
class SomedataXlsx(APIView):
renderer_classes = [XLSXRenderer, JSONRenderer]
def get(self, request):
queryset = Somedata.objects.all()
serializer = SomeDataSerializer(queryset, many=True)
return Response(serializer.data)
Looking at the mixin code it became clear they change the content-disposition header, and so since the DRF Response() takes a header argument I tried changing it, and it worked perfectly.
class SomedataXlsx(APIView):
renderer_classes = [XLSXRenderer, JSONRenderer]
def get(self, request):
user_sub_fund_data = Somedata.objects.all()
serializer = SomeDataSerializer(queryset, many=True)
return Response(serializer.data, headers={"content-disposition":"attachment; filename=mynewfilename.xlsx"})

Django response send file as well as some text data

Currently I am send a zip file in response from my Django-Rest controller, the zip file will get downloaded in front-end and this feature is working fine but now I want to send some data as well with the zip file in response, is there any way?
This is my Django-REST controller code
response = HttpResponse(byte_io.getvalue(),content_type='application/x-zip-compressed')
response['Content-Disposition'] = f'attachment;filename{my-sample-zip-file}'
return response
How can I send some data with this zip file on front-end?
You can do it with HTTP Request-Response module of django.
Refer: https://docs.djangoproject.com/en/2.2/ref/request-response/#telling-the-browser-to-treat-the-response-as-a-file-attachment
If you want to do it in production like code, you might also want to handle case where file is not available, set error and return neat. Also, better put that in a common file and then define download_file like below:
from common_library import FileResponse
from django.http import JsonResponse
def download_file( self ):
if self.error_response:
response = JsonResponse( { "error" : self.error_response } )
else:
response = FileResponse(self.report_file_abs_path, self.report_filename)
response['Content-Type'] = 'application/xlsx'
response['Content-Disposition'] = 'attachment; filename=' + self.report_filename
return response
NOTE: FileResponse is a user defined wrapper function which you can define.

Django REST framework FileField PUT Testcase

I have a model that contains a FileField which may not be blank. When creating tests for this model, I've run into the problem that I get errors when testing with PUT, while the exact same thing works when doing a POST.
As views I'm simply using generics.ListCreateAPIView for the POST destination and generics.RetrieveUpdateDestroyAPIView for the PUT destination, both work normally when using the API in browser.
The payload for the POST and PUT is created as follows:
uploaded_file = SimpleUploadedFile('TestCode4.c', "Testcode", content_type='text/plain')
self.valid_payload = {
'name': 'TestValid',
'test_file': uploaded_file
}
Then the working POST test looks as follows:
client = Client()
response = client.post(
reverse('code-list'),
self.valid_payload,
format='json'
)
And the PUT:
client = Client()
response = client.put(
reverse('code-detail', kwargs={'pk': 1}),
self.valid_payload,
format='json'
)
The POST returns 204 and creates a new object, while the PUT returns 415 with the following error:
{u'detail': u'Unsupported media type "application/octet-stream" in request.'}
I am unsure what is going wrong here, it seems that both the post and put are passing the SimpleUploadedFile data in the same way, though with put it somehow becomes an octet stream.
I figured out the problem Django's django.test.Client class does not support the 'PUT' method. Instead the REST framework provides the class rest_framework.test.APIClient, which does support PUT (and PATCH, etc).
The client.put() function now needs to be filled in a little differently (I was unable to get it to work with SimpleUploadedFile) as explained here: https://fodra.github.io/2017/05/31/testing-django-rest-api-with-image-field.html

Resources