在Django中模拟POST请求 [英] Simulating a POST request in Django

查看:319
本文介绍了在Django中模拟POST请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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

  from django.shortcuts import render 
从django.core.urlresolvers导入解析

def simulate(request,url = None,template_name =not_important.html):
如果url:
dv = resolve (url.split('?')[0])
return dv.func(request,* dv.args,** dv.kwargs)
else:
return render(request, template_name)

但是,我想将参数包含到包含的视图中,以便请求.REQUEST和request.GET对象也包括 foo spam


$ b $我不明白我怎么可以干净地做到这一点?据我了解请求.GET和request.REQUEST字典是不可变的,所以我不能只是这样做:

  import urlparse 

def simulate(request,url = None,template_name =not_important.html):
如果url:
dv = resolve(url.split('?' )[$]
qs =.join(url.split('?')[1:])
如果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实例是不可变的


。 GET对象和


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


为request.REQUEST对象



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



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

解决方案

request.GET / POST是 QueryDict 实例。根据 QueryDict 的文档,确实有不可变的 除非你复制它们


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

更新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没有记录,将会打破一天,大概甚至杀死一些小猫。自行决定使用自己的小猫。那就是说我喜欢你的用例,这是一个很好的主意。


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.

解决方案

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.

这篇关于在Django中模拟POST请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆