【问题标题】:Getting error 403 (CSRF token missing or incorrect)收到错误 403(CSRF 令牌丢失或不正确)
【发布时间】:2016-04-21 19:36:15
【问题描述】:

我需要一些电子邮件表单,我正在尝试这个:

views.py

def send_email(request):
    if request.method != 'POST':
        form = EmailForm()
        return render_to_response('mail_form.html', {'email_form': form})

    form = EmailForm(request.POST, request.FILES)   
    if form.is_valid():
        subject = form.cleaned_data['subject']
        message = form.cleaned_data['message']
        email = form.cleaned_data['email']
        attach = request.FILES['attach']
        try:
            mail = EmailMessage(subject, message, settings.EMAIL_HOST_USER, [email])
            mail.attach(attach.name, attach.read(), attach.content_type)
            mail.send()
            return render(request, 'mail_form.html', {'message': 'Sent email to %s'%email})
        except:
            return render(request, 'mail_form.html', {'message': 'Either the attachment is too  big or corrupt'})
        return render(request, 'mail_form.html', {'message': 'Unable to send email. Please try again later'})

forms.py

class EmailForm(forms.Form):
    email = forms.EmailField()
    subject = forms.CharField(max_length=100)
    attach = forms.Field(widget=forms.FileInput)
    message = forms.CharField(widget = forms.Textarea)

mail_form.html

...
{{message}}
<form method="post" action="">
    {% csrf_token %}
    {{ email_form.as_p }}
    <input type ="submit"  name = "send" value = "Send"/>
</form>
...

但我经常收到错误 403。我尝试了网络上的不同解决方案,但没有任何帮助。我做错了什么?我知道views.py中的csrf有问题,但不明白具体问题出在哪里。

【问题讨论】:

  • 您的缩进不正确。修复它。
  • @7stud 已修复,谢谢
  • 您是否启用了 CSRF 中间件django.middleware.csrf.CsrfViewMiddleware
  • 你使用的是什么版本的 django?
  • Pythonista 的答案似乎是正确的,至少我不再得到 403

标签: python django django-views django-csrf


【解决方案1】:

您的问题是render_to_reponse。它没有您可以添加的上下文实例,但render 会为您处理这个,所以为什么不直接使用它。您还可以重组您的视图,使其更清晰。

这是一个例子。

def send_email(request):

    if request.method == 'POST':
        form = EmailForm(request.POST, request.FILES)   
        if form.is_valid():
            subject = form.cleaned_data['subject']
            message = form.cleaned_data['message']
            email = form.cleaned_data['email']
            attach = request.FILES['attach']
            try:
                mail = EmailMessage(subject, message, settings.EMAIL_HOST_USER, [email])
                mail.attach(attach.name, attach.read(), attach.content_type)
                mail.send()
                messages.succes(request, 'Sent an email to %s' % email)
            except:
                messages.error(request, 'Either the attachment is too  big or corrupt')
    else:
        form = EmailForm()
        messages.info(request, "Send an email!")
    return render(request, 'mail_form.html', {'email_form': form})

然后您可以在模板中使用{% if messages %} 向用户显示您的消息/遍历它们并显示。

messages 这里来自django.contrib 所以你需要做from django.contrib import messages

【讨论】:

  • 谢谢,它有效!我会读一下render和render_to_response的区别!
【解决方案2】:
  1. 使用render_to_response 来自django.shortcuts
  2. 用于render_to_response context_instance = RequestContext(request)

这必须解决您的 csrf 令牌问题或阅读 https://docs.djangoproject.com/ja/1.9/ref/csrf/

【讨论】:

    【解决方案3】:

    像这样修改你的view.py

    from django.shortcuts import render
    from django.template import RequestContext
    def send_email(request):
    if request.method != 'POST':
        form = forms.EmailForm()
        return render_to_response('mail_form.html', {'email_form': form}, context_instance=RequestContext(request))
    
    ......
    ......
    

    【讨论】:

      【解决方案4】:

      你使用的是什么版本的 django?

      好吧,显然您在部分代码中使用了render()。问题出在您的 GET 代码中——您使用的是render_to_response()

      if request.method != 'POST':
          form = EmailForm()
          return render_to_response('mail_form.html', {'email_form': form})
      

      改用 render():

          return render(request, 'mail_form.html', {'email_form': form} )
      

      请参阅example in the Django docs

      您需要这样做的原因是因为使用 csrf 令牌您需要:

      1. 在表单中插入 csrf 令牌。

      2. 将 csrf 令牌作为 cookie 包含在请求/响应的标头中。

      render() 完成了 #2,但 render_to_response() 没有——除非你明确告诉它这样做,而你没有这样做。无论如何,django 1.9 docs 状态:

      render_to_response()

      这个函数在 render() 的引入之前并且有效 类似地,除了它不会使请求在 回复。 不推荐,并且很可能在 未来。

      【讨论】:

        猜你喜欢
        • 2017-09-10
        • 2013-08-15
        • 2013-12-03
        • 1970-01-01
        • 2016-07-01
        • 2020-09-19
        • 2018-03-15
        • 2014-09-10
        • 2015-10-15
        相关资源
        最近更新 更多