How can modify request.data in django REST framework

28,982

Solution 1

In case your API is APIView then you should use update function to expand your request data object without losing the data sent from the client-side.

request.data.update({"id": "10", "user": "tom"})

Solution 2

request.data should be an immutable QueryDict, rather than a string. If you need to modify it:

if isinstance(request.data, QueryDict): # optional
    request.data._mutable = True
request.data['age'] = "30"

The only reason you might check if it's an instance of QueryDict is so it's easier to unit test with a regular dict.

Solution 3

A good friend just took me to school on a much simpler approach than I illustrate above

class CreateSomething(CreateAPIView):
    model = Something
    queryset = Something.objects.all()
    serializer_class = SomethingSerializer

    perform_create(self,serializer):
    def perform_create(self,serializer):
        ip = self.get_ip()
        ## magic here: add kwargs for extra fields to write to db
        serializer.save(ip_addr=ip)

    def get_ip(self):
        x_forwarded_for = self.request.META.get('HTTP_X_FORWARDED_FOR',None)
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = self.request.META.get('REMOTE_ADDR',None)
        return ip

class SomethingSerializer(serializers.ModelSerializer):
    email = serializers.EmailField(validators=[UniqueValidator(queryset=Something.objects.all())])
    fieldA = serializers.CharField()
    fieldB = serializers.CharField()

    class Meta:
        model = Customer2
        fields = ['email','fieldA','fieldB','ip_addr']
        read_only_fields = ['ip_addr']

Solution 4

Generally request in drf views is rest_framework.request.Request instance. Following to it's source code (djangorestframework==3.8.2):

    @property
    def data(self):
        if not _hasattr(self, '_full_data'):
            self._load_data_and_files()
        return self._full_data

You can do:

request._full_data = your_data

Solution 5

It looks like a json string. To convert it to a dict you should do:

import json
data = json.loads(request.data)

then you can add extra attributes:

data['age'] = 30

Then you will have to make a new request because it seem like you cant just change the old one. This assumes that you are posting to /notes/:

from rest_framework.test import APIRequestFactory
factory = APIRequestFactory()
request = factory.post('/notes/', data, format='json')
Share:
28,982
John Kaff
Author by

John Kaff

Updated on January 16, 2022

Comments

  • John Kaff
    John Kaff over 2 years

    I am using Django REST Framework

    request.data = '{"id": "10", "user": "tom"}'
    

    I want to add extra attribute like "age": "30" before sending it to further like

        request.data = new_data
        response = super().post(request, *args, **kwargs)
    

    I have two issues

    1. Why request.data is coming as string rather than dict
    2. How can i update the request.data
  • John Kaff
    John Kaff over 8 years
    if i use request.data = json_data it says not able to set attribute on request
  • Alec Gerona
    Alec Gerona over 5 years
    It's so sad that there isn't a more intuitive way to do this. Probably a better mixin or some predefined function.
  • Csaba Toth
    Csaba Toth over 5 years
    BTW, you can also make some manipulations if you override the ModelViewSet's create and update methods.
  • JTW
    JTW over 5 years
    Yikes... although this works, DRF should have a cleaner way to accomplish this.
  • emanuel sanga
    emanuel sanga almost 3 years
    The best way to alter in a generic view is to override get_serializer method... This is a bit redundant as your serializer is not working at all if you are helpin it create
  • emanuel sanga
    emanuel sanga almost 3 years
    @Altus, there are ways to do that, or you mean djangoish ways?
  • validname
    validname over 2 years
    FYI accessing private methods or attributes is a really bad idea, but if you've got no other options you "can" do that.
  • isifzade
    isifzade about 2 years
    where "to_internal_value" method called?
  • Csaba Toth
    Csaba Toth about 2 years
    @isifzade it is called by the DRF framework as part of the deserialization workflow of the object. See related stackoverflow.com/questions/34196331/… and django-rest-framework.org/api-guide/fields
  • Alexander P
    Alexander P almost 2 years
    AttributeError: This QueryDict instance is immutable