Simulating a POST request in Django

戏子无情 提交于 2019-12-10 17:05:08

问题


Let's suppose I have the following url: /valid/django/app/path/?foo=bar&spam=eggs

I can simulate a request to this URL in Django thusly:

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'd like to include the parameters to the included view, so that the request.REQUEST and request.GET objects would also include foo and spam

I don't see how I can do this cleanly; as far as I understand the request.GET and request.REQUEST dictionaries are immutable so I can't merely 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'll get the error message

This QueryDict instance is immutable

for the request.GET object and

'MergeDict' object has no attribute 'update'

for the request.REQUEST object

In case anyone is wondering why I want to do this: I want to allow users to fill out a form and then, when they submit, if they aren't logged in it sends them to a login form that includes the original URL in a hidden field. After logging in, rather than redirecting back to that link (which would be a GET request) I want it to call the original view, with the request variables it originally had, so that it can use the same POST request.

And so of course in the process I'm also just interested in whether it would be possible to simulate a POST/GET request to a Django view when given a valid URL for the site.


回答1:


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

QueryDict instances are immutable, unless you create a copy() of them. That means you can't change attributes of request.POST and request.GET directly.

You can copy, update and re-assign 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 the 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 module django.utils.datastructures, and instanciated 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, will break one day, and probably even kill some kittens. Use at your own discretion and with your own kittens. That said I like your use case, it's a pretty good idea.




回答2:


It is true than request.GET/POST are immutable objects, but you can actually MAKE them mutable (this is potentially dangerous) and change them directly, like this :

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


来源:https://stackoverflow.com/questions/9370090/simulating-a-post-request-in-django

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!