Django Request

Django REST generic views are amazing, but working with request.data in Django REST framework can be tricky ..

Django REST generic views are amazing. It's hard to justify writing a flow-complete view by hand unless you're doing something so easy that doesn't require validation or other stuff.

Even then why leaving the enlightened path? There are situations however where you want to changerequest.data a bit in a generic view, and things will get tricky ..

So far you've worked with Django view methods and their input - a request object and parameters - as well as their output, consisting of generating a direct response or relying on a.

The problem: an example with CreateAPIView

CreateAPIView is a concrete view for handling the POST/return response lifecycle in a RESTful API. It accepts JSON POST requests.

After installing and configuring DRF all you need to start accepting requests is a subclass of CreateAPIView with a serializer. Example:

Here ContactSerializer is a DRF model serializer for a simple model. Here's the serializer:

And here's the model:

Django provides a powerful form library that handles rendering forms as HTML, validating user-submitted data, and converting that data to native Python types. Django also provides a way to generate forms from your existing models and use those forms to create and update data. Requests django 1 15434 To get query parameters from the request in the Django view, you need to access the GET attribute of the request. ' def filterqueryset(self, request, queryset, view): return queryset.filter(owner=request.user) We could achieve the same behavior by overriding getqueryset on the views, but using a filter backend allows you to more easily add this restriction to multiple views, or to apply it across the entire API. Rest Apis are so important in most applications to connect the backend and frontend parts. In this tutorial, I will show you how to build Python Rest Api CRUD with sending GET/POST/PUT/DELETE requests example using Django REST framework – a powerful and flexible framework for building Web APIs.

It's all bells and whistles until the frontend sends an object with exactly the same properties found in the serializer.

What I mean is that before sending the POST request from Fetch you have to build this object:

It's easy with a FormData if you have all the inputs with the appropriate name attributes. But, if you fail to do so DRF will respond with a 400 bad request. The solution? A bit of tweaking on the CreateAPIView subclass.

When we extend a Python class, here specifically CreateAPIView, we can also override inherited methods. If we snitch into the original CreateAPIView we can see a post method:

Seems a good spot for changing the request ..

AttributeError: This QueryDict instance is immutable

When Django REST frameworks receives a request, request.data is the entry point for your .. data. The JSON payload from your frontend will end up there.

Let's imagine a colleague doesn't know the exact shape for the request object and instead of sending this:

sends this:

Django

Let's also say you replicated the error on three different frontend and there's no easy way to come back.

How can we transform this JSON object inrequest.data to avoid a 400? Easier done than said! Just override the post method and mess up with the data:

If only was that easy! If we run this view we get AttributeError: This QueryDict instance is immutable. Surprise!

request.datain fact is a Django QueryDict which turns out to be immutable.

The only way to change it is to copy the object and modify the copy. But there's no way to swap back request.data with your own object because at this stage request is immutable too.

So where do we intercept and swap request.data?

NOTE: if you want to test this view check out DRF: testing POST requests.

get_serializer to the rescue

When subclassing CreateAPIView we get access to all the methods defined in CreateModelMixin and GenericAPIView:

Parallels Inc., a global leader in cross-platform solutions, makes it simple for customers to use and access the applications and files they need on any device or operating system. We help businesses and individuals securely and productively use their favorite devices and preferred technology, whether it’s Windows®, Mac®, iOS, AndroidTM, Chromebook, Linux, Raspberry Pi or the Cloud. Seamless Use Windows side-by-side with macOS (no restarting required) on your MacBook ®, MacBook Pro, iMac ®, iMac Pro, Mac mini ® or Mac Pro ®.Share files and folders, copy and paste images and text & drag and drop files between Mac and Windows applications. Easy Set-Up Parallels Desktop automatically detects what you need to get started so you are up and going within minutes! Next, set Parallels to full screen mode, and it will maximize to fill the external monitor. Parallels display settings. Information Parallels Desktop will be able to use any display that is successfully connected to Mac. You do not need to connect a display to virtual machine directly.

Here's the UML diagram from Pycharm:

CreateModelMixin is pretty simple, with three methods: create, perform_create, get_success_headers.

Request.session

create in particular is interesting because it forwards request.data to another method named get_serializer. Here's the relevant code:

get_serializer is not found directly on CreateModelMixin, it lives on GenericAPIView:

Django Request Timeout

Bingo! What if we override this method in our view to intercept and change kwargs['data']?

Intercepting request.data in the right place

Django Request Body

In our view we can override get_serializer with our own version:

If request.data has wrong fields we make a copy, we modify the fields, and we place the copy on the data keyword argument:

Now the serializer will receive the expected data shape and won't complain anymore. In case the fields are ok instead we go straight to the happy path.

NOTE: in the example I'm using the warlus operator from Python 3.8.

Wrapping up

Django Request Query Params

The request object in Django REST framework is immutable and so request.data. To alter the payload we can make a copy, but there's no way to swap the original object with our copy, at least in a post method.

Django Request Object

A custom override of get_serializer from the generic DRF view can solve the issue in a cleaner way.

Thanks for reading!

Django Request Get Data

Resources