Search code examples
djangoviewcsrfverification

CSRF verification failed in Django project update, and RequestContext solution not working


I have a Django project in which trying to 'update' (clicking on the button) causes the following error:

CSRF verification failed. Request aborted.

Help
Reason given for failure:

    CSRF token missing or incorrect.

I have viewed various questions and answers that suggest that adding RequestContext is the solution, but I have tried something to that effect tailored to my code, and still am unable to get it working.

Original code views.py is below

#USERS (register) view.py
from django.shortcuts import render,redirect
from django.contrib.auth.forms import UserCreationForm
from django.contrib import messages #this allows us flash messages for testing
from django.contrib.auth.decorators import login_required
from .forms import UserRegisterForm
from .forms import UserUpdateForm
from .forms import ProfileUpdateForm

from django.contrib.auth.decorators import login_required

def register(request):
    if request.method =='POST':
        #this UserRegisterForm is created in forms.py and inherits from UserCreationForm (the ready made form)
        form = UserRegisterForm(request.POST) #create a form that has the data that was in request.POST
        if form.is_valid(): #is the form valid (do you have a username like this already, passwords match?
            form.save()
            username = form.cleaned_data.get('username')
            messages.success(request,f'Account created for {username}, you can now login.')
            return redirect('login')

    else:
        form =UserRegisterForm() #if the form input is invalid, render the empty form again


    return render(request, 'users/register.html',{'form':form})


@login_required #this is a decorator (adds functionality to an existing function)
def profile(request):
    if request.method =='POST':
        u_form =UserUpdateForm(request.POST,instance=request.user)
        p_form =ProfileUpdateForm(request.POST, request.FILES,instance=request.user.profile)

        if u_form.is_valid() and p_form.is_valid():
            u_form.save()
            p_form.save()
            messages.success(request,f'Your Account has been directed')
            return redirect('profile')

    else:   
        u_form =UserUpdateForm(instance=request.user)
        p_form =ProfileUpdateForm(instance=request.user.profile)


    context={
            'u_form': u_form,
            'p_form': p_form
        }

    return render(request,'users/profile.html',context)

As mentioned I also tried:

return render(request,'users/profile.html',context_instance=RequestContext(request))

I also tried adding the below to imports

from django.shortcuts import get_object_or_404, render,redirect

Note: I do not wish to try the 'remove middleware' alternative.

The profile.html file code is below and I have included the CSRF token correctly, as far as I know:

{% extends "socialmedia/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
    <div class="content-section">
      <div class="media">
        <img class="rounded-circle account-img" src="{{ user.profile.image.url }}">
        <div class="media-body">
          <h2 class="account-heading">{{ user.username }}</h2>
          <p class="text-secondary">{{ user.email }}</p>
        </div>
      </div>
     <form method="POST" enctype="multipart/form-data>
        {% csrf_token %}
        <fieldset class="form-group">
            <legend class="border-bottom mb-4">Profile Information</legend>
            {{u_form|crispy}}
            {{p_form|crispy}}
        </fieldset>
        <div class="form-group">
            <button class="btn btn-outline-info" type="submit">Update....</button>
        </div>
    </form>
   </div>
{% endblock content %}

Finally, for context, here is forms.py

from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from .models import Profile

class UserRegisterForm(UserCreationForm): #form that inherits from the usercreationform
    email = forms.EmailField()

    class Meta: 
        model = User 
        #when this form validates it creates a new user
        #type the fields to be shown on your form, in that order.
        fields = ['username','email','password1','password2']   

class UserUpdateForm(forms.ModelForm):
    email = forms.EmailField()

    class Meta: 
        model = User 
        fields = ['username','email']

class ProfileUpdateForm(forms.ModelForm):
    class Meta:
        model= Profile
        fields=['image']

Question: What is causing the error and what do I need to add/change in the code as it stands?

I also came across an answer on StackOverflow which said this "The problem is you are not returning the result. Remember that the view is a function. You need to return render_to_response(...) not just call it (which is also why by removing CSRF you got the didn't return an HttpResponse error)" ....can someone explain this in my context? I don't understand what it means or how to implement it either.


Solution

  • It looks like it should work, however I noticed you seem to be missing a quote at the end here

     <form method="POST" enctype="multipart/form-data>