简体   繁体   English

在Django中模拟POST请求

[英]Simulating a POST request in Django

Let's suppose I have the following url: /valid/django/app/path/?foo=bar&spam=eggs 我们假设我有以下网址: /valid/django/app/path/?foo=bar&spam=eggs

I can simulate a request to this URL in Django thusly: 我可以在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)

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 但是,我想将参数包含在包含的视图中,以便request.REQUEST和request.GET对象也包含foospam

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: 据我所知,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)

Or I'll get the error message 或者我会收到错误消息

This QueryDict instance is immutable 此QueryDict实例是不可变的

for the request.GET object and 对于request.GET对象和

'MergeDict' object has no attribute 'update' 'MergeDict'对象没有属性'update'

for the request.REQUEST object 对于request.REQUEST对象

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

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

request.GET/POST are QueryDict instances. request.GET / POST是QueryDict实例。 According to the documentation on QueryDict , there are indeed "immutable" unless you clone them : 根据QueryDict上的文档, 除非你克隆它们,否则确实是“不可变的”:

QueryDict instances are immutable, unless you create a copy() of them. QueryDict实例是不可变的,除非您创建它们的副本()。 That means you can't change attributes of request.POST and request.GET directly. 这意味着您无法直接更改request.POST和request.GET的属性。

You can copy, update and re-assign QueryDicts as such: 您可以复制,更新和重新分配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']}>)

The trick to update the MergeDict is to override its dicts attribute as such: 更新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']}>)

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) . 请注意, MergeDict在模块django.utils.datastructures中定义,并在django.core.handlers.wsgi (和django.core.handlers.modpython)中实例化为: self._request = datastructures.MergeDict(self.POST, self.GET)

DISCLAMER : MergeDict is not documented, will break one day, and probably even kill some kittens . DISCLAMER :MergeDict没有记录,有一天会破坏,甚至可能会杀死一些小猫 Use at your own discretion and with your own kittens. 您可以自行决定使用自己的小猫。 That said I like your use case, it's a pretty good idea. 这就是说我喜欢你的用例,这是个不错的主意。

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 / 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM