I am trying to test my update method on my viewset. The viewset is a modelviewset taken from drf. To update i would need to send a put request. As this is not always supported there are 2 ways to tell the server i am making a put request, the first which does not fit my needs is to use an additional field to form called _method and set it to put. As i need to post json data i need to use the second way, which uses the X-HTTP-Method-Override header.
To post my data in the testcase i use the following code:
header = {'X_HTTP_METHOD_OVERRIDE': 'PUT'}
response = client.post('/model/1/', content_type='application/json', data=post_data_clean, **header)
But unfortunately the result I get is {'detail':'Method POST not allowed.'}. I tested the behavior of the server using a addon (Postman) where i specified the X-HTTP-Method-Override header too. No exception is raised. I need to know now how to correctly pass the header to the django test client, otherwise testing will get really annoying over here.
You need to specify header as 'HTTP_X_HTTP_METHOD_OVERRIDE' instead of 'X_HTTP_METHOD_OVERRIDE' i.e. add HTTP_ at the beginning of the header.
header = {'HTTP_X_HTTP_METHOD_OVERRIDE': 'PUT'}
response = client.post('/model/1/', content_type='application/json', data=post_data_clean, **header)
From the Django documentation:
HTTP headers in the request are converted to META keys by converting
all characters to uppercase, replacing any hyphens with underscores
and adding an HTTP_ prefix to the name. So, for example, a header
called X-Bender would be mapped to the META key HTTP_X_BENDER.
Also, you can pass headers to the constructor of the Client:
from django.test import Client
client = Client(HTTP_USER_AGENT="Mozilla/5.0 ...", HTTP_X_USER_ID="982734")
This way every request will contain default headers.
PS: This approach is valid for DRF TestApiClient and ApiRequestFactory.
Related
I have this url which returns the json data of my models but I don't know how to create a unit test for a url like this
path("list/", views.json_list, name="json_list"),
I'm not really sure what is being asked. A test like this
url = reverse('myapp:json_list')
response = client.get( url)
body = response.content.decode()
is going to fail if anything is wrong with the url definition. (Specifically, reverse will fail if the name doesn't exist, and for an url with arguments, if what you supply as kwargs isn't accepted by the url definition).
As for validating the response, we can't help without knowing a lot more about what is expected. Presumably, you will locate the start of some JSON text in body, feed it to json.loads, and make sure the data is as expected. But I don't think that's what is being asked.
So I've got a python application that is using requests.post to make a post request with json headers, body info, etc.
Problem is that in my dictionary that gets sent as headers, I have a variable that often contains character groups like %25"" or "%2F", etc. I've seen this cause problems before if sent in body data, but that can be fixed by sending the body data as a sting rather than a dictionary. Haven't figured out how to make this work with the headers though, as you can't simply delimit the parameters with an ampersand like in body data.
How do I make sure that my cookie value is not altered in the process of the post request?
For instance, headers :
Host : blahblah.com
Connection : Keep-Alive
Cookie : My sensitive string with special characters
etc.
Note : Nothing server-side can be changed. The python application is being used for hired pentesting services.
A common technique for sending data that becomes a mess when transmitted is to encode it, especially as base64
Sender:
import base64
...
encoded_data = "base64:{}".format(base64.b64encode(data))
Receiver:
import base64
...
if encoded_data.startswith("base64:"):
data = base64.b64decode(encoded_data.split(':')[1])
I'm trying to send a POST request with params that contain null values and None just gets ignored. Besides that, I'm unsure about whether or not False is sent as false.
For example:
requests.post("http://myurl.com/address/", data = {"parentValue":{"value1":False,"value2":None}})
and the required params server-side are
{"parentValue":{"value1":false, "value2":null}}
tl;dr: I need false and null on the server side as params from a POST request, how do I send them using Python requests?
rather than using data=simplejson.dumps({"parentValue":{"value1":False,"value2":None}}) you should use
json = {"parentValue":{"value1":False,"value2":None}}
As roganjosh suggested, json.dumps() on the object needed, works.
When to use RequestHandler.get_argument(), RequestHandler.get_query_argument() and RequestHandler.get_body_argument()?
What is the use-case for each of them?
Also what does the request.body and request.argument do in these cases? Which are to be used in which scenarios?
And, is there a request.query or something similar too?
Most HTTP requests store extra parameters (say, form values) in one of two places: the URL (in the form of a ?foo=bar&spam=eggs query string), or in the request body (when using a POST request and either the application/x-www-form-urlencoded or multipart/form-data mime type).
The Request.get_query_argument() looks for URL parameters, the RequestHandler.get_body_argument() lets you retrieve parameters set in the POST body. The RequestHandler.get_argument() method retrieves either a body or a URL parameter (in that order).
You use Request.get_argument() when you explicitly don't care where the parameter comes from and your endpoint supports both GET and POST parameters. Otherwise, use one of the other methods, to keep it explicit where your parameters come from.
The Request.get_*_argument methods use the request.body_arguments and request.query_arguments values (with request.arguments being their aggregate), decoded to Unicode. request.body is the undecoded, unparsed raw request body; and yes, there is an equivalent self.query containing the query string from the URL.
Consider a request coming from this url /messages/compose/(?P<recipients>[\+\.\w]+)/ where recipients is usernames separated by + sign. After success (message to recipients successfully sent) i am doing:
#success_url = 'message_send_success'
recipients = '+'.join([obj.username for obj in recipients]) #converting them back to original string
reverse(success_url, kwargs={'recipients': recipients})
This is the url to whom it match:
url(r'^/messages/success/(?P<recipients>[\+\.\w]+)$', 'site.views.message_send_success', name='message_send_success')
But it will show all recipients in the url, is there any away i can hide those recipients string to be displayed in url and can access it in request??
Maybe you want to use base64 library:
>>> base64.b64encode("what is that?")
'd2hhdCBpcyB0aGF0Pw=='
>>> base64.b64decode("d2hhdCBpcyB0aGF0Pw==")
'what is that?'
Note: if you want to have more safety urls, you should do some translations on that string (otherwise other user that know base (en)coding will easily decode your value.
Not if you're using a redirect. Django has a "shared-nothing" architecture, which means that between one request and the next no user state persists on the server. For this reason, Django can't (automatically) "remember" what your recipients were before the redirect, so it can access them in the next HTTP request.
What are your reasons for wanting to hide them? Is there sensitive information you can't send back to the client, or something like that? One option to avoid that is to simply repeat the information the client sent (i.e. the original recipients parameter) and have the success view redo the operations that compose did on them.