【问题标题】:Simulating a POST request in Django在 Django 中模拟 POST 请求
【发布时间】:2012-03-11 07:44:27
【问题描述】:

假设我有以下网址:/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”对象没有“更新”属性

对于 request.REQUEST 对象

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

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

【问题讨论】:

    标签: python django django-views django-urls


    【解决方案1】:

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

    QueryDict 实例是不可变的,除非您创建它们的 copy()。这意味着您不能直接更改 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)

    免责声明:MergeDict 没有记录,有一天会坏掉,甚至可能杀死一些小猫。由您自行决定并与您自己的小猫一起使用。那就是说我喜欢你的用例,这是个好主意。

    【讨论】:

    • 我认为更新是一个就地操作。您可能需要先分配副本,然后再更新它
    • 当然,谢谢jdi! FTR 我实际上粘贴了一个经过测试的 POC :)
    • 很高兴你喜欢这个主意;在某个时候,我会尝试提取它并将其发布到 github 或其他地方。如果我最终能弄清楚,你所要做的就是用装饰器包装一个视图,它会自动为你处理它。
    【解决方案2】:

    确实,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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多