Omar Elabed
Omar Elabed

Reputation: 41

Django not accepting data from python-requests.patch()

I'm trying to send data from a service running with python through a http PATCH request to another running Django with Django API Rest Framework using requests.

The SomeAccount has a field appUserId which is now -1.

Here is the some_sender.py who knows about the app_user_id (=77, e.g.):

auth = ('someusrname', 'somepwd')
data = {"appUserId": app_user_id}
url = 'myapi:8000/someaccounts/1'
r = requests.patch(url, data=data, auth=auth)
print r.status_code
#> 200

When I check the value of the item at GET /someaccounts/1 it still has appUserId=-1.

While debugging, in Django I get the request, but without any data - it's just an empty dict.

Here is how I it looks in Django:

mysite/myapp/urls.py:

from django.conf.urls import include, url
from rest_framework import routers
from . import views

router = routers.DefaultRouter()

router.register(r'someaccount', views.SomeAccountViewSet)
# ...
urlpatterns = [
    url(r'^', include(router.urls)),
    # ...
]

mysite/myapp/models.py:

from django.db import models
# ...
class SomeAccount(models.Model):
    """
    Some account can include all the data related to some user's account.
    """
    # ...
    appUserId = models.BigIntegerField(blank=True, null=True)

mysite/myapp/views.py:

class SomeAccountViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows some accounts to be viewed or edited.
    """
    queryset = SomeAccount.objects.all()
    serializer_class = SomeAccountSerializer

mysite/myapp/serializers.py:

from models import SomeAccount
# ...
class SomeAccountSerializer(serializers.ModelSerializer):
    id = serializers.ReadOnlyField()

    class Meta:
        model = SomeAccount
        fields = ('url', 'id', 'appUserId')
        depth = 3
        partial = True

    def update(self, someAccount, account_data):
        if 'appUserId' in account_data:
            someAccount.appUserId = account_data.pop('appUserId')
        someAccount.save()
        return someAccount

In SomeAccountSerializer when debugging on the incoming request I get the following values:

I tried to send the same values through the Postman Google Chrome plugin and it worked.

I also tried to set the content-type header:

with application/x-www-form-urlencoded:

requests.patch(
    url, data=data, auth=auth,
    headers={'content-type': 'application/x-www-form-urlencoded'}
)

with application/form-data:

requests.patch(
    url, data=data, auth=auth,
    headers={'content-type': 'application/form-data'}
)

with application/json:

requests.patch(
    url, json=json.dumps(data), auth=auth,
    headers={'content-type': 'application/json'}
)

without being successful.

EDIT: python-requests is sending the request correctly. The problem probably lies in how Django is handling it.

Upvotes: 4

Views: 1189

Answers (2)

Stuart Buckingham
Stuart Buckingham

Reputation: 1784

Just ran into this same issue. Was missing the trailing slash on the URL. When Django redirected to the URL with the trailing slash, it seemed to drop the payload of the PATCH.

Upvotes: 1

stoer
stoer

Reputation: 38

You should check your network traffic to make sure where the problem appears. If I use

import requests

app_user_id = 7
auth = ('someusrname', 'somepwd')
data = {'appUserId': app_user_id}
url = 'http://localhost:8000/someaccounts/1'

r = requests.put(url, data=data, auth=auth)
print r.status_code

and open a local socket with netcat (nc -l 8000) I am getting the data form encoded:

PUT /someaccounts/1 HTTP/1.1
Host: localhost:8000
Content-Length: 11
Accept-Encoding: gzip, deflate
Accept: */*
User-Agent: python-requests/2.8.1
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Authorization: Basic c29tZXVzcm5hbWU6c29tZXB3ZA==

appUserId=7

Upvotes: 0

Related Questions