Django Querydict fancy behavior: bundles of POST-dictionary in one key

I experience really strange behavior when using a test client in django.

I am using POST to send data to my django application. I usually do this from an iPhone application and / or html test form. On the server side, as I understand it:

 def handle_query(request): print request q = con.QueryLog() q.ID = request.POST.get('ID', '') q.device = request.POST.get('device-model', '') .... 

This print statement looks as you would expect, i.e. each parameter in the mail request turns into a key in the dictionary:

POST: QueryDict: {u'app-version ': [u'3.0'], u'server-version ': [u'v3d0'],

However, I started to write some tests using the Django test client, and no matter what I try, the dictionary of POST parameters that I send in the mail request is grouped into one key in QueryDict . Let me illustrate with some code:

class SearchTest (TestCase): def setUp (self): pass

 def test_search(self): request = HttpRequest() data = '{"amzn_locale": "com"}' # request._raw_post_data = data resp = self.client.post( '/is/', data=data, content_type='application/x-www-form-urlencoded', # content_type='application/json', ) 

The same print statement on the server side shows an inexplicable grouping of the dictionary into a string:

 POST: QueryDict: {u'{"amzn_locale":"com"}': [u'']}>, 

If I install data into a real dictionary, the same

 data = {"amzn_locale": "com"} 

Setting request._raw_post_data does not change anything. Also does not change

 content_type='application/json' 

Any help would be greatly appreciated. From this stackoverflow question, it seems like I'm not the first to come across this . Iphone Json POST request to Django server creates QueryDict in QueryDict

+5
source share
3 answers

The problem is that you are supplying content_type. Since you did this, the client expects a string with urlencoded, e.g.

 "username=hi&password=there&this_is_the_login_form=1" 

instead of a dictionary like

 {'username': 'hi', 'password': 'there', 'this_is_the_login_form': 1} 

If you delete the content_type kwarg, everything will be fine.

Edit: as it turns out, the test client will look for a url encoded string if you pass any content_type content other than MULTIPART_CONTENT β€” content_type will only be used to determine which encoding to use for encoding this string with url encoding. This is described here . The corresponding bit reads:

If you provide content_type (e.g. text / xml for the XML payload), the data content will be sent as is in the POST request using the content_type in the HTTP Content-Type header.

If you did not specify a value for content_type, values ​​in the data will be transmitted with the content type multipart / form-data. In this case, the key-value pairs in the data will be encoded as a multi-part message and used to create a POST data payload.

+7
source

Edit: And, of course, right on the line above the one I started to look at, this is the correct answer. post_data is handled differently based on content_type. See answer below. No need to apply the changes below.

So, it seems that what happens is that the data you enter into the message is immediately compressed by the string encoding function into a dict string representation that QueryDict cannot read later on the line. I do not know what the intended behavior is, but if you urlencode the message data before receiving serialization, then it should at least come in the required form in QueryDict. In django / test / client.py we see line 244

 post_data = smart_str(data, encoding=charset) 

which just aligns the dict and serializes it. A possible fix would be to apply the same formatting as GET before serialization, therefore

 post_data = smart_str(urlencode(data, doseq=True), encoding=charset) 

This seems reasonable to me, although I cannot guarantee that it has no consequences elsewhere. It looks like you could do the above conversion in your code before calling client.post, but I have not tested this.

+1
source

But you declared it as a string - you have single quotes around the value for data .

0
source

Source: https://habr.com/ru/post/918277/


All Articles