CSRF verification failed, 'CSRF token missing or incorrect' - django

This has been asked many times before and I have read all of those answers, but none of them worked for me so I'd like to try again.
When I try to submit a Django form with username and password, I get this error message:
'CSRF token missing or incorrect'.
The CSRF token is not missing.
Here is where I included it in my form in my .html template:
In index.html:
<form name="loginform" action="/notes/index/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit"/>
{% for field, errors in form.errors.items %}
{{ errors }}
{% endfor %}
</form>
In views.py:
class LoginForm(forms.Form):
username = forms.EmailField()
password = forms.CharField(widget=forms.PasswordInput())
def index(request):
if request.method == 'POST':
print("Received POST")
form = LoginForm(request.POST)
if form.is_valid():
print("FORM is Valid")
else:
print("FORM is NOT VALID")
template = loader.get_template('index.html')
context = {
'username': 'Benny',
'form': LoginForm(),
}
return HttpResponse(template.render(context))
I also have csrf middleware in settings. I am trying to avoid using #csrf_exempt as this app will go into production down the line.

I got it to work but not sure why this fixes it. Can anyone clarify?
I changed:
return HttpResponse(template.render(context))
to:
return HttpResponse(template.render(context, request=request))
I thought the request was automatically carried out by render()? So I'm not sure why I had to add request=request.

Related

How to use form_validate() with CustomForm in Django

I'm creating an app in which I'd like to use my own custom login form with a captcha field. My intention is to do this without using an external library (except for requests) but I couldn't add captcha field to my custom form in forms.py, so I added it directly to login.html but for some reason when I do form.is_valid() it returns an error.
I've already seen the solutions in Django - adding google recaptcha v2 to login form and Adding a Recaptcha form to my Django login page but as I said, I'd like to do this without using an external library.
views.py
...
def login_view(request):
if request.method == 'POST':
form = CustomLoginForm(request.POST)
result = is_recaptcha_valid(request)
print(result) # prints True
if form.is_valid():
username = form.cleaned_data['username']
email = form.cleaned_data['email']
password = form.cleaned_data['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
# Redirect to index
messages.success(request, "Logged in.")
return HttpResponseRedirect(reverse('orders:index'))
else:
messages.error(request, "Invalid credentials.")
else:
print("error")
return render(request, 'registration/login.html', {'form': CustomLoginForm()})
else:
form = CustomLoginForm()
return render(request, 'registration/login.html', {'form': form})
forms.py
class CustomLoginForm(AuthenticationForm):
email = forms.EmailField(
error_messages={
'required': 'Please enter your email.',
'invalid': 'Enter a valid email address.'
},
help_text='Email',
)
login.html
<form class="" action="{% url 'orders:login' %}" method="post">
{% csrf_token %}
{% for field in form %}
<p>
{{ field.label_tag }}<br>
{{ field }}
{% if field.help_text %}
<small style="color: grey">{{ field.help_text }}</small>
{% endif %}
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<!-- ReCAPTCHAV3 -->
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<div class="g-recaptcha" data-sitekey='key-here'></div>
<button class="btn btn-success" type="submit" name="">Login</button>
<!-- <input type="hidden" name="next" value="{{ next }}"> -->
</form>
is_recaptcha_valid() function already returns True so I didn't share that. I'm a beginner in Django, so if you can please explain in two words what I've done wrong instead of just posting the answer, I'd be grateful. Thank you for your time.
The AuthenticationForm is slightly different than the others..
If your check AuthenticationForm class, AuthenticationForm 's first arguments is not data like others form:
class AuthenticationForm(forms.Form):
...
def __init__(self, request=None, *args, **kwargs):
...
Thats why you need to pass request.POST to data.
So update your code like this:
def login_view(request):
if request.method == 'POST':
form = CustomLoginForm(data=request.POST)
...

invalid PasswordChangeForm

Heyho,
I created a model Profile with a OnetoOneField to User. In account_settings view I want to either give the possibility to change the profile information or reset the password. Changing Profile-Information works fine, but when I try to change the password, my PasswordChangeForm is always invalid. Can somebody tell me where my mistake is?
Here's the view:
def account_settings(request, id):
user = Profile.objects.get(id=id)
if request.method == 'POST' and 'passwordchange' in request.POST:
user_form = PasswordChangeForm(request.user, prefix='password')
if user_form.is_valid():
user_form.save()
update_session_auth_hash(request, user)
messages.success(request, 'Your password was successfully updated!')
else:
messages.error(request, 'Please correct the error below.')
return redirect('profile', user.id)
elif request.method == 'POST' and 'profilechange' in request.POST:
profile_form = ProfileForm(request.POST, instance=request.user.profile,prefix='profil')
if profile_form.is_valid():
profile_form.save()
return redirect('account_settings',user.id)
#else:
#messages.error(request, _('Please correct the error below.'))
else:
user_form = PasswordChangeForm(user=request.user, prefix='password')
profile_form = ProfileForm(instance=request.user.profile,prefix='profil')
return render(request, 'app/accountform.html', {'profileuser': user,'user_form': user_form,'profile_form': profile_form})
the template:
<div class="col-md-9">
<div class="profile-content">
<form method="post" >
{% csrf_token %}
{{ profile_form.as_p }}
<button type="submit" name="profilechange">Ă„nderungen speichern</button>
</form>
<form method="post" >
{% csrf_token %}
{{ user_form.as_p }}
<button type="submit" name="passwordchange">Passwort ändern</button>
</form>
Abbrechen
</div>
</div>
You are not passing the POST data to the form, which is why it is failing to validate. You need to pass the POST data when initialising it:
user_form = PasswordChangeForm(request.user, data=request.POST, prefix='password')
if user_form.is_valid():
# This should work now

django view redirects to URL it shouldn't

I have the following view
def edit_booking(request, pk=None):
if not request.user.is_authenticated:
raise Http404
agent = Agent.objects.get(user=request.user)
booking = get_object_or_404(Booking, pk=pk)
form = BookingForm(request.POST or None, instance=booking)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
return HttpResponseRedirect(instance.get_absolute_url())
elif form.errors:
messages.error(request,"There was a problem, please try again")
context = {
"form": form,
}
return render(request,'booking_form.html', context)
I use the following urls.py
urlpatterns = [
url(r'^booking/create', create_booking, name="create-booking"),
url(r'^booking/$', booking_list, name="booking-list"),
url(r'^booking/(?P<pk>\d+)/$', booking_detail, name="booking-detail"),
url(r'^booking/(?P<pk>\d+)/edit', edit_booking, name="edit-booking"),
]
For some reason when I try to submit the form after editing some booking (e.g. http://127.0.0.1:8000/booking/24/edit) I am automatically redirected to (http://127.0.0.1:8000/booking/24/).
As far as I can tell django is not processing any further code in the view. I tried to figure out with simple print("something") to see where in the code it ends up but it just goes to the url right away as soon as I submit from the template. For completeness sake this is the template:
{% extends 'base.html' %}
<div class="col-sm-6 col-sm-offset 3">
{% block content %}
<form method="POST" action=".">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save"/>
</form>
{% endblock %}
</div>
".", which you used as the action of the form, is interpreted by browsers as "the base of the current path directory". Since you have not used a trailing slash in your /edit URL, the browser submits the form to the nearest base, ie /booking/24.
You should always use a trailing slash:
url(r'^booking/create/$', create_booking, name="create-booking"),
url(r'^booking/$', booking_list, name="booking-list"),
url(r'^booking/(?P<pk>\d+)/$', booking_detail, name="booking-detail"),
url(r'^booking/(?P<pk>\d+)/edit/$', edit_booking, name="edit-booking"),
You need to check for the request method otherwise it will redirect on initial form rendering because django uses the same view for initial rendering and submitting the form.
if request.method == 'POST':
if form.is_valid():
instance = form.save(commit=False)
instance.save()
return HttpResponseRedirect(instance.get_absolute_url())
elif form.errors:
messages.error(request,"There was a problem, please try again")
else:
context = {
"form": form,
}
return render(request,'booking_form.html', context)

Django authentication works on a page, but not another

I've been working on Django Authentication, but I have stumbled on a problem: login works on a page (the "post detail" page of the blog), but not on the homepage.
This is the part of the base.html that handles this header
{% if user.is_authenticated %}
<span class="glyphicon glyphicon-plus"></span>
<span class="glyphicon glyphicon-edit"></span>
<p class="top-menu">Hello, {{ user.first_name }}!<small> (Log out)</small></p>
{% else %}
<form>
{% csrf_token %}
{% if next %}
<input type="hidden" name="next" value="{{ next }}" />
{% endif %}
{{ login_form.as_p }}
</form>
{% endif %}
The view seems good to me, anyway here it is
def login(request):
if request.method == 'POST':
login_form = CustomLoginForm(request.POST)
email = request.POST.get('email')
password = request.POST.get('password1')
user = authenticate(email=email, password=password)
if user is not None:
if user.is_active:
auth_login(request, user)
return HttpResponseRedirect('/')
else:
return HttpResponse("Your Blog account is disabled.")
else:
print "Invalid login details: {0}, {1}".format(email, password)
return HttpResponse("Invalid login details supplied. Get back to the homepage.")
else:
login_form = CustomLoginForm()
return render(request, 'blog/post_list.html', {})
def post_list(request):
posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('-published_date')
user = CustomUser.objects.all()
user_form = CustomUserCreationForm()
login_form = CustomLoginForm()
return render(request, 'blog/post_list.html', {'posts': posts, 'user_form': user_form, 'login_form': login_form, 'user': user})
I think the core of the problem could be on either the header of the base.html file or on the view.
This is what I see on the homepage (even when I'm logged in)
This is what I see on the post-detail page (and that's what I should see on the homepage too)
Any thoughts?
Your problem is here:
user = CustomUser.objects.all()
and then
return render(request, 'blog/post_list.html',
{'posts': posts, 'user_form': user_form,
'login_form': login_form, 'user': user})
You are passing a queryset result consisting of CustomUser objects as user in your request context. It overwrites the user variable assigned by the django.contrib.auth.context_processors.auth context processor.
To solve the problem, simply change the name of the template variable to something else, such as:
return render(...
'users': user})

Vexed by csrf_token -- though it's there

I keep getting a verification failed missing csrf_token. I'm very puzzeled/stuck on this. as you can see by my code below it's in fact there. Any help will be very much appreciated.
Django==1.6.1 btw
MIDDLEWARE_CLASSES = (.... 'django.middleware.csrf.CsrfViewMiddleware', ...)
class BaseSignUp(View):
model = None
form = None
template = None
def get(self, request):
return render_to_response(self.template,
{'user_form': UserCreateForm, 'form': self.form})
def post(self, request):
user = UserCreateForm(request.POST)
obj = self.form(request.POST)
if user.is_valid():
user.save()
else:
return render_to_response(self.template, {'user_form': user, 'form': obj})
<form method="post">
{% csrf_token %}
<table>
{{ user_form }}
{{ form }}
</table>
<button type="submit">Save</button>
</form>
Found the answer here Django - {% csrf_token %} was used in a template, but the context did not provide the value
I was missing the context_instance=RequestContext(request) in the post/get methods in the veiw
Lesson learned: just user render.