首页 > 解决方案 > 如何使用 Django 模拟 POST 到 URL

问题描述

我想创建一个视图函数来模拟用户在 处获取表单url、设置表单的输入变量之一 ( my_flag) 并提交该表单。我尝试了两种不同的方法,但都失败了。

方法1:使用python请求获取并发布到url

def simulate_post(request):
    url = request.build_absolute_uri(reverse('my_app:form_view', args=[666]))
    response = requests.get(url)
    csrftoken = response.cookies['csrftoken']
    print("TOKEN =", csrftoken)
    response = requests.post(url, data={'my_flag': True, 'csrftoken': csrftoken}, headers={'Referer': url})
    return response

这种方法失败如下。显然我什至没有成功传递 CSRF 令牌:

TOKEN = EXFI2xoKxHounDIRnqdrPwLpdXGe3zuZATErKINTuxJsgzV7Oj6lPP6kzsjQVc7z
Forbidden (CSRF cookie not set.): /form_view/666/
[12/Feb/2021 16:44:02] "POST /form_view/666/ HTTP/1.1" 403 2868
Internal Server Error: /simulate_post/
Traceback (most recent call last):
  File "/Users/me/.local/share/virtualenvs/myapp-MCS7ouoX/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/Users/me/.local/share/virtualenvs/myapp-MCS7ouoX/lib/python3.8/site-packages/django/utils/deprecation.py", line 96, in __call__
    response = self.process_response(request, response)
  File "/Users/me/.local/share/virtualenvs/myapp-MCS7ouoX/lib/python3.8/site-packages/django/middleware/clickjacking.py", line 26, in process_response
    if response.get('X-Frame-Options') is not None:
AttributeError: 'Response' object has no attribute 'get'

方法二:使用 RequestFactory

def simulate_post(request):
    url = request.build_absolute_uri(reverse('my_app:form_view', args=[666]))
    factory = RequestFactory()
    factory.user = request.user
    response = factory.get(url)
    response = factory.post(url, data={'my_flag': True})
    return response

这种方法失败如下:

Internal Server Error: /simulate_post/
Traceback (most recent call last):
  File "/Users/me/.local/share/virtualenvs/myapp-MCS7ouoX/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/Users/me/.local/share/virtualenvs/myapp-MCS7ouoX/lib/python3.8/site-packages/django/utils/deprecation.py", line 96, in __call__
    response = self.process_response(request, response)
  File "/Users/me/.local/share/virtualenvs/myapp-MCS7ouoX/lib/python3.8/site-packages/django/middleware/clickjacking.py", line 26, in process_response
    if response.get('X-Frame-Options') is not None:
AttributeError: 'WSGIRequest' object has no attribute 'get'

在这两种情况下,我的模拟 POST 似乎都没有返回正确的响应。我怎样才能让它工作?

更新:方法 3 [不完整]

遵循@schillingt 和 Iain 的建议来重构我试图利用的搜索/表单视图的内容,如果我知道如何继续,这是第三种可能的方法。

发出第一个 HTTP 请求,即 GET,基本上相当于这样:

context = search_context(request, data)
return render(request, 'myapp/display.html', context)

context包括一个form变量,它是搜索的形式。如果我可以根据需要设置表单并变成requestPOST,它将产生我需要的内容。虽然不知道怎么...

标签: djangodjango-viewsdjango-formscsrfhttpresponse

解决方案


您可以使用resolve来获取将为给定 url 调用的实际视图函数。将从 a 生成的 POST 请求传递给由RequestFactory返回的视图resolve应该可以工作

from django.shortcuts import reverse
from django.test import RequestFactory
from django.urls import resolve


def simulate_post(request):
    url = reverse('my_app:form_view', args=[666])
    factory = RequestFactory()
    post_request = factory.post(url, data={'my_flag': True})
    resolved = resolve(url)
    return resolved.func(post_request, *resolved.args, **resolved.kwargs)

推荐阅读