Hahore-kun Hahore-kun - 7 months ago 25
Python Question

Getting error 403 (CSRF token missing or incorrect)

I'm need some email form and I'm trying this:

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>
...


But constantly I get an error 403. I tried different solutions from the web, but nothing helped. What I'm doing wrong? I'm understand that something wrong with csrf in views.py, but don't understand where is the problem concretely.

Answer

Your problem is render_to_reponse. It doesn't have the context instance you can add it, but render handles this for you so why not just it instead. Also you can restructure your view to be a bit cleaner.

Here's one example.

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})

Then you can use {% if messages %} in your template to display your messages to the user / iterate over them and display.

messages here is from django.contrib so you'd need to do from django.contrib import messages

Comments