1

我期待POST来自第 3 方服务器。我知道我需要使用@csrf_exempt装饰器来允许来自第 3 方服务器的帖子。我在 Ubuntu 12.04 上使用 Django 1.4 和 Python 2.7。

现在,我的视图将生成一个未绑定的表单,该表单将包含供用户填充的字段以及包含原始信息的隐藏字段POST。因此,第一个POST将启动第二个POST

第二个POST将从我的服务器发送到我服务器上的另一个视图。我试图弄清楚如何CSRF为我的表单生成令牌。

我正在尝试完全按照我在文档中阅读的内容进行操作。

我的views.py代码:

from django.core.context_processors import csrf
from django.shortcuts import render_to_response
from gateway_interface.post_handling import PostHandling

@csrf_exempt
def requestNewPaymentInfo(request):

    c = {}
    c.update(csrf(request))

    # Gather information posted
    if (request.method == "POST"):
        # Create the initialization dictionary based on POST values
        postHandling = PostHandling()
        post_dict = postHandling.createDictionary(request)

        # Create the form
        form = addPaymentForm(initial = post_dict)

        return render_to_response('requestNewPaymentInfo.html', { 'form' : form }, c)

你现在在模板方面做什么?!?同样,从文档中我认为我应该执行以下操作:

<form action="/addPayment/" method="post">
   {% csrf_token %}
</form>

我通过POST从 3rd 方服务器进行测试来测试这一点。有时我会看到完全生成的表单似乎是一个有效的CSRF令牌。

有时我会看到如下所示的失败:

Django Version: 1.4
Python Version: 2.7.3
Installed Applications:
('django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.sites',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.admin',
 'gateway_interface')
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware')


Traceback:
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py" in get_response
  111.                         response = callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/views/decorators/csrf.py" in wrapped_view
  77.         return view_func(*args, **kwargs)
File "/home/tokeniz/tokeniz/gateway_interface/views.py" in requestNewPaymentInfo
  64.         return render_to_response('requestNewPaymentInfo.html', { 'form' : form }, c)
File "/usr/local/lib/python2.7/dist-packages/django/shortcuts/__init__.py" in render_to_response
  20.     return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader.py" in render_to_string
  178.         context_instance.pop()

Exception Type: TypeError at /requestNewPaymentInfo/
Exception Value: pop expected at least 1 arguments, got 0

然后我最终会得到这个错误:

Forbidden (403)
CSRF verification failed. Request aborted.

一旦我收到CSRF verification failed错误,我将继续收到此错误,直到我清除 cookie 并重新开始。

谁能告诉我我做错了什么?我可以看到它与我如何生成CSRF令牌有关。根据文档中的内容,我不明白该过程是如何工作的。c在我看来是什么?我正在填充信息并传递给render_to_response. 好的,但是如何在模板中使用它?

我的模板应该是这样的:

<form action="/addPayment/" method="post">
   {% c.csrf_token %}
</form>

如果不是,为什么?Django 怎么知道这c包含CSRF令牌?

任何帮助将不胜感激。

4

1 回答 1

4

为了解决您的问题,让我可以澄清一些事情。

简而言之,Django 的模板系统使用两个数据:上下文模板

当您在模板文件中放置一个要显示的变量时{{ foo }},django 将在相应的上下文实例dict查找该变量的值。

现在render_to_response,您作为第二个参数 a 传递给它的dict内容本质上是您想要放入模板上下文中的数据,因此您可以使用它。第三个参数是一个Context实例,而不是数据本身,当您需要自定义事物时它会很有用。

好的,让我们看看你的例子,

return render_to_response('requestNewPaymentInfo.html', { 'form' : form }, c)

在这里,您在阅读文档示例时犯了一个错误,您将c其作为上下文实例,而不是上下文数据,因此您的令牌甚至没有进入模板,并且您在 django 期望 Context 对象的地方遇到了所有那些奇怪的错误,但只有得到了字典。

所以要修复,你只需要在模板数据中传递 csrf 令牌:

c.update({'form': form})
return render_to_response('requestNewPaymentInfo.html', c)

在模板内部:

{% csrf_token %}

我建议为程序员阅读模板系统解释,它写得很好。

于 2012-07-14T00:16:24.783 回答