我有一个登录表单,我希望在所有视图中都可用,因此我创建了一个上下文处理器,将此表单添加到每个加载的上下文中。
问题是表单模板上的{% csrf_token %}
不会使用CSRF令牌值呈现隐藏的输入标记。
这是settings.py
中的context_processor顺序:
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.core.context_processors.static',
'django.core.context_processors.tz',
'django.contrib.messages.context_processors.messages',
'django.core.context_processors.request',
'django.core.context_processors.csrf',
'absolute.context_processors.absolute',
'myproject.app.context_processors.base',
)
然后处理器本身在app/context_processors.py
:
from django.contrib.auth.forms import AuthenticationForm
def base(request):
context = dict()
if not request.user.is_authenticated():
context['login_form'] = AuthenticationForm()
return context
表单模板:
{% load i18n %}
<form method="post" action="{% url "django.contrib.auth.views.login" %}">
{% csrf_token %}
<input type="hidden" name="next" value="{% if request.GET.next %}{{ request.GET.next }}{% else %}{{ request.get_full_path }}{% endif %}" />
{{ login_form.as_p }}
<input type="submit" class="button success expand" value="{% trans 'Login' %}" />
</form>
此表单的HTML输出:
<form action="/accounts/login/" method="post">
<input type="hidden" value="/" name="next">
<p><label for="id_username">Usuário:</label> <input type="text" name="username" maxlength="254" id="id_username"></p>
<p><label for="id_password">Senha:</label> <input type="password" name="password" id="id_password"></p>
<input type="submit" value="Login" class="button success expand">
</form>
提交时出现的错误:
CSRF verification failed. Request aborted.
但是,由于我只使用基于类的视图,如果我添加csrf_protect
装饰器,表单将起作用,但是像这样我必须在我的所有方法中声明dispatch
方法的观点:
from django.views.decorators.csrf import csrf_protect
class HomeView(TemplateView):
template_name = 'home.html'
@method_decorator(csrf_protect)
def dispatch(self, *args, **kwargs):
return super(HomeView, self).dispatch(*args, **kwargs)
我放弃了通过创建登录表单页面将AuthenticationForm放在我的所有视图上。无论如何,如果有人可以帮我找到解决这个问题的方法,它仍然会很棒。
答案 0 :(得分:3)
我花了几个小时来解决类似于你在此描述的问题。 {% csrf_token %}
没有呈现任何内容,我在调试模式下看到了这一点:
defaulttags.py:66:UserWarning:模板中使用了{%csrf_token%},但上下文未提供该值。这通常是由于不使用RequestContext引起的。
我使用的是从TemplateView继承的简单视图:
class MenuIndexView(TemplateView):
template_name = 'menu/index.html'
def get_context_data(self, **kwargs):
kwargs = super().get_context_data(**kwargs)
session = self.request.session
kwargs['zip_code'] = session.get('zip_code')
kwargs['calendar'] = helpers.get_menu_calendar(date.today() + timedelta(days=1), timedelta(days=14))
kwargs['forms'] = {'zip_code': forms.ZipCodeForm({'zip_code': session.get('zip_code')})}
return kwargs
在Django&#39; s之后,我意识到在生成标记时几乎没有任何上下文可用(Django的CsrfTokeNode
文件defaulttags.py
:
class CsrfTokenNode(Node):
def render(self, context):
csrf_token = context.get('csrf_token', None)
if csrf_token:
if csrf_token == 'NOTPROVIDED':
return format_html("")
else:
return format_html("<input type='hidden' name='csrfmiddlewaretoken' value='{}' />", csrf_token)
else:
# It's very probable that the token is missing because of
# misconfiguration, so we raise a warning
if settings.DEBUG:
warnings.warn(
"A {% csrf_token %} was used in a template, but the context "
"did not provide the value. This is usually caused by not "
"using RequestContext."
)
return ''
在代码的这一点上,我只看到了上下文中的一个项目,并带有zip_code
键。
我打开了主模板文件并意识到我犯了一个菜鸟错误 - 这是我的主要模板menu/index.html
:
{% extends 'base.html' %}
{% block content %}
<div class="menu-order-meta zip_calendar">
<div class="ink-grid align-center">
<div class="column-group gutters half-vertical-padding medium">
{% include 'partials/menu/zip-code.html' with zip_code=zip_code only %}
</div>
</div>
</div>
{% endblock %}
我通过部分模板包含表单,并且我明确地限制了该部分模板中的可用上下文 - 注意with zip_code=zip_code only
声明 - (通过这样做,隐式转换csrf_token
上下文处理器不可用)。
答案 1 :(得分:0)
也许你错过了MIDDLEWARE_CLASSES中的django.middleware.csrf.CsrfViewMiddleware?
MIDDLEWARE_CLASSES = (
....
'django.middleware.csrf.CsrfViewMiddleware',
....
)