1

我需要使用render_to_string,但我不能使用

@csrf_protect

并通过

context_instance=RequestContext(request)) 

到 render_to_string 因为我认为装饰器期望的是 HttpResponse,而不是 SafeString。

如何将 csrf_token 放入字符串中的表单中?

“NoneType”对象没有属性“COOKIES”

编辑:感谢您的评论,这里有一些澄清:

我正在创建一个类似于“portlets”的“面板”系统,其中面板在数据库中配置(包括将面板呈现为字符串的 python 函数的名称 - 面板函数在运行时从它们在数据库)。

为了将这些面板放入页面中,我创建了一个自定义模板标签,它从数据库中读取所需面板的名称,将它们呈现为字符串,然后将一大块 html(作为字符串)返回到页面呈现。(这允许用户选择为他们显示哪些面板。)

我的问题是其中一个面板(使用 render_to_string 将模板呈现为字符串的简单 python 函数)中有一个表单。

我需要将 CSRF 字段插入到该表单中,因为它被呈现为字符串。

4

4 回答 4

5

我已经解决了这个问题,但我仍然非常想要一个好的解决方案。

面板功能现在看起来像:

def render_to_s(request, *args, **kwargs):
    panelDisplays = PanelDisplay.listAll()
    csrf_token_value = request.COOKIES['csrftoken']

    c = {"panelDisplays": panelDisplays, "csrf_token_value": csrf_token_value}
    return render_to_string('panels/config.html', c)

虽然模板现在包括:

<div style='display:none'><input type='hidden' name='csrfmiddlewaretoken' value='{{ csrf_token_value }}'/></div>
于 2012-04-28T08:12:58.760 回答
1

在您看来,您使用 request.COOKIES['csrftoken'] 我不确定 cookie 是否始终可用,因此我的解决方案是在每个请求上生成 csrf 令牌。

from django.middleware.csrf import get_token

def render_to_s(request, *args, **kwargs):
    panelDisplays = PanelDisplay.listAll()
    csrf_token_value = get_token(self.request)

    c = {"panelDisplays": panelDisplays, "csrf_token_value": csrf_token_value}
    return render_to_string('panels/config.html', c)
于 2012-07-02T09:44:37.297 回答
0

视图应始终返回 HttpResponse(或其祖先之一)。所以你应该 return HttpResponse(your_rendered_string),但它和 call 是一样的render_to_response。如果您需要修改响应正文,您也可以使用响应来完成:

response = render_to_response(...)
response.content = response.content.replace('A', 'B')
return response
于 2012-04-28T04:57:54.343 回答
0

这是一个完整解决方案的示例。一切都源于这篇优秀的帖子。

这是基于您希望在网站的多个页面上包含邀请表单而不重复自己的情况。

邀请.widgets.py:

from invitations.forms import InvitationForm
from django.middleware.csrf import get_token
from django.template.loader import render_to_string

def invitation_widget_function (request):
    # ... blah blah blah 
    # ... stuff I don't want 
    # ... to repeat in every view
    invitation_form = InvitationForm ()
    csrf_token_value = get_token(request)
    context = { 'invitation_form': invitation_form, 
                'csrf_token_value': csrf_token_value }
    return render_to_string ( 'invitation_widget_template.html', context )

邀请小部件模板.html:

<form action="/whatever/" method="post">
    {% csrf_token %}  {# don't do this because it won't work in streamed output #}
    {# do this instead: #}
    <div style='display:none'>
    <input type='hidden' name='csrfmiddlewaretoken value='{{ csrf_token_value }}'/>
    </div>
    {{ invitation_form }}
    <button type="submit">Invite Someone</button>
</form>

视图.py:

from invitations.widgets import invitation_widget_function 
from django.shortcuts import render         

def page_view (request):
    invitation_widget = invitation_widget_function(request)
    context = { 'invitation_widget': invitation_widget }
    return render (request, 'page_template.html', context )

page_template.html:

<body>
    <div>
    {% include "some_normal_template.html" %} {# takes context from page_view() #}

    {{ invitation_widget }} {# not an include, but a fully rendered string #}
    {# took context from invitation_widget_function() -- has csrf token included #}
    </div>
</body>
于 2013-04-05T19:32:49.193 回答