在Django中模拟POST请求

时间:2012-02-20 23:39:23

标签: python django django-views django-urls

假设我有以下网址:/valid/django/app/path/?foo=bar&spam=eggs

我可以在Django中模拟对此URL的请求:

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)

但是,我想将参数包含在包含的视图中,以便request.REQUEST和request.GET对象还包括foospam

我看不出我怎么能干净利落地做到这一点;据我所知,request.GET和request.REQUEST字典是不可变的,所以我不能只做类似的事情:

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)

或者我会收到错误消息

  

此QueryDict实例是不可变的

表示request.GET对象和

  

'MergeDict'对象没有属性'update'

表示request.REQUEST对象

如果有人想知道我为什么要这样做:我想允许用户填写表单然后,当他们提交时,如果他们没有登录,它会将它们发送到包含原始的登录表单隐藏字段中的URL。登录后,而不是重定向回到该链接(这将是一个GET请求),我希望它使用最初的请求变量调用原始视图,以便它可以使用相同的POST请求。

当然,在这个过程中,我也只是感兴趣的是,当给出网站的有效URL时,是否可以模拟对Django视图的POST / GET请求。

2 个答案:

答案 0 :(得分:14)

request.GET / POST是QueryDict个实例。根据{{​​3}}上的文档,确实存在“不可变”,除非您克隆它们

  

QueryDict实例是不可变的,除非您创建它们的副本()。这意味着您无法直接更改request.POST和request.GET的属性。

您可以复制,更新和重新分配QueryDicts

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']}>)

更新MergeDict 的技巧是覆盖其 dicts 属性:

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']}>)

请注意 MergeDict 在模块 django.utils.datastructures 中定义,并在 django.core.handlers.wsgi (和django)中实例化.core.handlers.modpython):self._request = datastructures.MergeDict(self.POST, self.GET)

DISCLAMER :MergeDict没有记录,有一天会破坏,甚至可能杀死一些小猫。您可以自行决定使用自己的小猫。这就是说我喜欢你的用例,这是个不错的主意。

答案 1 :(得分:0)

这是真的比request.GET / POST是不可变对象,但你实际上可以让它们变得可变(这有潜在危险)并直接更改它们,如下所示:

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