I have been trying to set up a test version of a captcha form using the Django CMS, Mezzanine. It displays the captcha, but when I submit the form I get the error:
Forbidden (403)
CSRF verification failed. Request aborted.
Help
Reason given for failure:
CSRF token missing or incorrect.
In general, this can occur when there is a genuine Cross Site Request Forgery, or when Django's CSRF mechanism has not been used correctly. For POST forms, you need to ensure:
Your browser is accepting cookies.
The view function uses RequestContext for the template, instead of Context.
In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL.
If you are not using CsrfViewMiddleware, then you must use csrf_protect on any views that use the csrf_token template tag, as well as those that accept the POST data.
You're seeing the help section of this page because you have DEBUG = True in your Django settings file. Change that to False, and only the initial error message will be displayed.
You can customize this page using the CSRF_FAILURE_VIEW setting.
The behavior is the same with Firefox and Chrome (with or without incognito). I am using Python 3.4, Django 1.6.7, and Mezzanine 3.1.0. I have tried to fix the problem in several ways:
1) My html template:
<body>
<h3>Captcha</h3>
<form method="POST">
{% csrf_token %}
<input name="item_text" id="id_new_item" placeholder="Enter item">
<br>
{{ form.captcha }}
<input type="submit" value="Submit">
</form>
</body>
2) In my settings.py file:
TEMPLATE_CONTEXT_PROCESSORS = (
...
"django.core.context_processors.csrf",
)
MIDDLEWARE_CLASSES = (
...
"django.middleware.csrf.CsrfViewMiddleware",
)
3) In my captcha_test.views.py:
from django.views.decorators.csrf import csrf_protect
from django.shortcuts import render_to_response
from django.http import HttpResponse
from captcha_test.forms import CaptchaTestForm
#csrf_protect
def captcha_page(request):
if request.POST:
form = CaptchaTestForm(request.post)
if form.is_valid():
human = True
return HttpResponseRedirect('/')
else:
form = CaptchaTestForm()
return render_to_response('captcha.html', locals())
My forms.py file, if this helps at all:
from django import forms
from captcha.fields import CaptchaField
class CaptchaTestForm(forms.Form):
item_text = forms.CharField()
captcha = CaptchaField()
Any insights? Thanks for your help!
You must ensure that:
The view function uses RequestContext for the template, instead of Context.
But you use:
return render_to_response('captcha.html', locals())
And, from the documentation to render_to_response:
By default, the template will be rendered with a Context instance (filled with values from dictionary). If you need to use context processors, render the template with a RequestContext instance instead.
So adding context_instance=RequestContext(request) should solve the problem.
Related
been searching a lot for fixing my issue.. New to django and might be missing a very simple logic here and looking for some help..
I have created a form in html page called thispage.html as below:
<form action="{% url 'getvaluefromform' %}" method="POST">{% csrf_token %}
<input type="text" name='mytitle' placeholder="enter title">
<input type="submit" value="save">
</form>
then I updated views.py with the below code:
from django.shortcuts import render
def index(request):
return render(request,'thispage.html')
def getvaluefromform(request):
mytitle = request.POST.get('mytitle')
print(mytitle)
return render(request,'thispage.html')
finally my urls.py has this part:
from dhango.urls import path
from . import views
urlpatterns = [
path('',views.index,name='index'),
path('getvaluefromform',views.getvaluefromform,name='getvaluefromform')
]
Problem:
when I use this I am able to get the input vallue however the url is changing to '/getvaluefromform' and when I remove 'getvaluefromform' from the url section and just keep it '' then the code view index gets picked up.
Is there a way I can call the second function when button is clicked without moving to the new path. Please advise.
P.S - I am deliberately not using a model form because I want to build a raw sql query based on user input and then run the query to get the results/ create a new table on the database.
Django forms:
If you want to get POST data from a form without changing routes you have a very good example in the official documentation.
HTML forms:
If you're not into Django forms you can do as stated below.
def getvaluefromform(request):
if request.method == 'POST':
mytitle = request.POST.get('mytitle')
return render(request,'otherpage.html')
return render(request,'thispage.html')
What this will do is basically check if there's a POST request, get the form data and if there's a GET request, you'll just render the defined page.
If you must have two different routes, I suggest using Javascript.
I need some help with django
I have kind of landing page with form, which need to have 3 different states.
Flow looks like this: enter email -> check database for user with that email -> render login or register form, still in same template.
Code looks like this:
.html
// lots of code
<form method="POST" id="form">
{{ form.as_p }}
{% csrf_token %}
<input type="submit" value="send">
</form>
// lots of code
and in views.py i have render method with context
return render(
request,
'apply.html',
context,
)
where in context i placed simple standard django form like:
class ApplyForm(forms.Form):
email = forms.CharField()
phone = forms.CharField()
Is there and way to change ApplyForm to LoginForm or RegisterForm after sending POST from first one, without refreshing whole page?
I though about injecting all three forms to context, sending some ajax request, and then differentiate which form should be displayed, but I'm not sure how could it be done...
thanks in advance!
I have made a simple form inside a html file whose path is www.site.com/posts/5. Whenever the form is submitted, it redirects back to the same page i.e www.site.com/posts/5 displaying a message given by user in the form.
However, whenever the form is submitted it doesn't call the foobar view.
The urls.py, views.py and html files are as follows:-
urls.py
urlpatterns = [
path('posts/<int:foo>',user_views.display, name="display",
path('posts/<int:foo>',user_views.foobar, name="makefoo"),
]
views.py
def foobar(request, foo):
#do something
html file
<form name="fooform" action= "{% url 'makefoo' 5 %}" method = "post">
{% csrf_token %}
<input type="text" name="FOO_BODY" maxlength="300" required>
<input type="submit" value="comment">
<input type="reset" value="clear">
</form>
Edit : user_views is just from user import views as user_views
You can not attach two views to the same URL. The {% url ... %} template tag, only generates a URL for that path. But if there is a "url clash", then it is possible that the requests ends up in the other view.
You thus should define another URL, or encode the post logic in the display view. In case of a POST request, you can thus first take the necessary steps, and then for example return a redirect to the page, such that we can again render the page:
def display(request, foo):
if request.method == 'POST':
# do something
return redirect(display, foo=foo)
#do something else (original code)
return HttpResponse(..)
This is the famous Post/Redirect/Get web development design pattern [wiki]. This is usually better than returning a HTTP response directly in the POST, since if the user performs a refresh, the POST will be performed a second time.
As mentioned in the comment by #williem, you have two path() defined in the urls.py.
Always First matching route will be picked up from the url route table. So whenever r^'posts/' is requested it will call the display() from the user_views, so it will never go to foobar(). Either remove the route with display() or change the sequence. Also, I assume you imported the user_views.
Reference:
https://docs.djangoproject.com/en/2.1/topics/http/urls/
I am working on a project where an organization will login and then logout if they want. But somehow the logout functionality is not working. No redirect is happening and the user is not able to logout.
# urls.py
urlpatterns = [
path('logout',views.user_logout,name = 'logout')
]
# views.py
def user_logout(request):
if request.method == "POST":
logout(request)
return HttpResponseRedirect('login')
# template:
<a href="#" onClick="document.getElementById('logoutform').submit()" class="btn">
Logout</a>
<form id="logoutform" method="POST" action="{% url 'logout' %}">
{% csrf_token %}
<input type="hidden">
</form>
The page just reloads and no redirect happens.
I think you've made this more complicated than it needs to be. Django comes with a LogoutView, and it allows logouts with GET requests. You could use that logout view, or change your own to:
from django.shortcuts import redirect
def user_logout(request):
logout(request)
return HttpResponseRedirect('login') # assumes you have a URL pattern with name='login'.
Note that HttpResponseRedirect('login') will redirect to the relative URL 'login', so you might end up at /logout/login. You should either use the absolute URL (e.g. HttpResponseRedirect('/login/')), reverse the URL (e.g. return HttpResponseRedirect(reverse('login')), or use the redirect shortcut which takes care of reversing for you.
Once you have changed the logout view, you can remove the form and simply link to the logout page.
Logout
Beginner at Django here, I've been trying to fix this for a long time now.
I do have 'django.middleware.csrf.CsrfViewMiddleware' in my middleware classes and I do have the token in my post form.
Heres my code, what am I doing wrong?
from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
from chartsey.authentication.forms import RegistrationForm
from django.template import RequestContext
from django.core.context_processors import csrf
def register(request):
if request.method == 'POST':
c = RequestContext(request.POST, {})
form = RegistrationForm(c)
if form.is_valid():
new_user = form.save()
return HttpResponseRedirect("/")
else:
form = RegistrationForm()
return render_to_response("register.html", {'form': form, }, )
Here's my Template:
{% block content %}
<h1>Register</h1>
<form action="" method="POST"> {% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
{% endblock %}
Update: This answer is from 2011. CSRF is easy today.
These days you should be using the render shortcut function return render(request, 'template.html') which uses RequestContext automatically so the advice below is outdated by 8 years.
Use render https://docs.djangoproject.com/en/2.2/topics/http/shortcuts/
Add CSRF middleware https://docs.djangoproject.com/en/2.2/ref/csrf/
Use the {% csrf_token %} template tag
Confirm you see the CSRF token value being generated, AND submitted in your form request
Original Response
My guess is that you have the tag in the template but it's not rendering anything (or did you mean you confirmed in the actual HTML that a CSRF token is being generated?)
Either use RequestContext instead of a dictionary
render_to_response("foo.html", RequestContext(request, {}))
Or make sure you have django.core.context_processors.csrf in your CONTEXT_PROCESSORS setting.
https://docs.djangoproject.com/en/dev/ref/contrib/csrf/
Or add the token to your context manually
Just add this to your views
return render_to_response("register.html", {'form': form, }, context_instance = RequestContext(request))
It will work!!
Try using render instead of render_to_response:
from django.shortcuts import render
render(request, "foo.html", {})
Django - what is the difference between render(), render_to_response() and direct_to_template()?
As stated in the link above it was introduced in Django 1.3 and automatically uses RequestContext
for Django version 3.0 add the below annotation
#csrf_protect
def yourfunc(request):
return render(request, '../your.html', None)
And don't forget add the below tag in your field
<form action="add/" method="post">
{% csrf_token %}
...
</form>
If you are not using CsrfViewMiddleware, then you must use csrf_protect on any views that use the csrf_token template tag, as well as those that accept the POST data.
The addition of RequestContext is the key when using render_to_response as mentioned by #Yuji 'Tomita' Tomita and #Njogu Mbau. However, what initially threw me off when I was struggling with this problem was that I had to add RequestContext to both the function in views.py that initially loads the template and to the function in views.py that handles the submission from the template.
Also, just for reference, here are some other links that discuss this same problem
Django - CSRF token missing or incorrect
Django 403 CSRF token missing or incorrect
Django --CSRF token missing or incorrect
Django CSRF Cookie Not Set *
Also got this error randomly on some pages after I installed django-livereload-server. Uninstalling django-livereload-server did the trick.
I had this issue too, but honestly, I hit refresh on my browser a few minutes later without changing anything and it worked that time. I had this message in my command line as so it might provide a clue as to what was causing the issue:
Not Found: /css/reset/reset.css
[03/Jul/2020 20:52:13] "GET /css/reset/reset.css HTTP/......
DJANGO/AJAX WORKFLOW FULL METHOD IS HERE :)
const url = "{% url 'YOUR_URL_NAME' pk=12345 %}".replace(/12345/, id.toString());
$.ajax({
type: 'POST',
url: url,
data: {'id':id, "csrfmiddlewaretoken": '{{csrf_token}}'},
beforeSend: function() { $('#response').text('Please wait ...'); },
success: function (response) {
console.log(response)
},
error: function (response) {
console.log(response)
}
})
Hope It Will Work !!!
What worked for me was commenting out the below line from my settings.py
'django.middleware.csrf.CsrfViewMiddleware'