获取错误403(CSRF令牌丢失或不正确)

时间:2016-04-21 19:36:16

标签: python django django-views django-csrf

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

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有问题,但不明白具体问题在哪里。

4 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

  1. 使用render_to_response
  2. 中的django.shortcuts
  3. render_to_response context_instance = RequestContext(request)
  4. 中使用

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

答案 2 :(得分:0)

只需像这样修改你的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))

......
......

答案 3 :(得分:0)

  

你使用的是什么版本的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。

  3. render()完成#2,但render_to_response()没有 - 除非你明确告诉它,你没有。无论如何,django 1.9 docs州:

      

    <强> render_to_response()这个

         

    此函数在引入render()之前有效   同样地,除了它没有使请求可用   响应。 不推荐使用 ,可能会弃用   将来