Simulating a POST request in Django

Suppose I have the following url: /valid/django/app/path/?foo=bar&spam=eggs

I can simulate a request to this url in Django as follows:

 from django.shortcuts import render from django.core.urlresolvers import resolve def simulate(request, url=None, template_name="not_important.html"): if url: dv = resolve(url.split('?')[0]) return dv.func(request, *dv.args, **dv.kwargs) else: return render(request, template_name) 

However, I would like to include the parameters in the included view so that request.REQUEST and request.GET objects also include foo and spam

I do not understand how I can do this cleanly; as far as I understand the words request.GET and request.REQUEST are immutable, so I can’t just do something like:

 import urlparse def simulate(request, url=None, template_name="not_important.html"): if url: dv = resolve(url.split('?')[0]) qs = "".join(url.split('?')[1:]) if qs: request.REQUEST.update(urlparse.parse_qs(qs)) request.GET.update(urlparse.parse_qs(qs)) return dv.func(request, *dv.args, **dv.kwargs) else: return render(request, template_name) 

Or I will get an error

This instance of QueryDict is immutable

for the request.GET object and

MergeDict object does not have attribute 'update'

for request.REQUEST object

In case someone wonders why I want to do this: I want to allow users to fill out the form and then when they submit, if they are not logged in, they send them to the login form, which includes the original URL in hidden field. After logging in, instead of redirecting back to this link (this will be a GET request), I want it to call the original view with the request variables that it originally had so that it could use the same POST request.

And therefore, of course, in this process I am also interested in whether it is possible to simulate a POST / GET request in a Django view if it is given a valid URL for the site.

+4
source share
2 answers

request.GET / POST - QueryDict instances. According to the QueryDict documentation, there really are "immutable" ones unless you clone them :

QueryDict instances are immutable unless you create them (). This means that you cannot directly modify the request.POST and request.GET attributes.

You can copy, update, and reassign QueryDicts as such:

 ipdb> request.GET <QueryDict: {u'x': [u'1']}> ipdb> request.POST <QueryDict: {}> ipdb> request.REQUEST MergeDict(<QueryDict: {}>, <QueryDict: {u'x': [u'1']}>) ipdb> new_post = request.POST.copy() ipdb> new_post.update(request.GET) ipdb> request.POST = new_post ipdb> request.POST <QueryDict: {u'x': [u'1']}> ipdb> request.GET <QueryDict: {u'x': [u'1']}> ipdb> request.REQUEST MergeDict(<QueryDict: {}>, <QueryDict: {u'x': [u'1']}>) 

The trick to update MergeDict is to override its dicts attribute as such:

 ipdb> request.REQUEST MergeDict(<QueryDict: {}>, <QueryDict: {u'x': [u'1']}>) ipdb> request.REQUEST.dicts = (request.POST, request.GET) ipdb> request.REQUEST MergeDict(<QueryDict: {u'x': [u'1']}>, <QueryDict: {u'x': [u'1']}>) 

Note that MergeDict is defined in the django.utils.datastructures module and defined in django.core.handlers.wsgi (and django.core.handlers.modpython) as such: self._request = datastructures.MergeDict(self.POST, self.GET) .

DISCLAMER : MergeDict is not documented, it will break one day and may even kill some kittens . Use as you wish and with your kittens. However, I like your use case, this is a pretty good idea.

+14
source

This is true than request.GET / POST - immutable objects, but you can really change them (this is potentially dangerous) and change them directly, for example:

 request.GET._mutable = True # make some changes, for example delete something inside if 'var_name' in request.GET: del request.GET['var_name'] request.GET._mutable = False 
0
source

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


All Articles