Hey, I am following this tutorial to learn to make a wiki page with Django. However, it is made in django 0.96 and I use Django 1.3 so there are some things that are different. Some I already fixed myself, however this one I can't seem to make it work.
I made a form that submits data to a view. This is the form:
<form method="post" action"/wikicamp/{{page_name}}/save/">{% csrf_token %}
<textarea name="content" rows="20" cols="60">{{content}}</textarea><br>
<input type="submit" value="Save Page"/>
</form>
and the /wikicamp/{{page_name}}/save/ url redirects to the save_page view:
from django.http import HttpResponseRedirect
from django.core.context_processors import csrf
def save_page(request, page_name):
c = {}
c.update(csrf(request))
content = c.POST["content"]
try:
page = Page.objects.get(pk=page_name)
page.content = content
except Page.DoesNotExist:
page = Page(name=page_name, content=content)
page.save()
return HttpResponseRedirect("wikicamp/" + page_name + "/")
However the problem is that I get this error:
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:
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.
So I read through some of the documentation, like http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#how-to-use-it. I tried to do that however and it still gave the same error.
So: Anyone an idea how to handle form post data well with Django 1.3?
I think it has something to do with: The view function uses RequestContext for the template, instead of Context. but i don't now what it is.
btw, in my terminal which shows the http request of the localhost it says this: A {% csrf_token %} was used in a template, but the context did not provide the value. This is usually caused by not using RequestContext.
Django puts data in request. POST when a user submits a form with the attribute method="post" . Line 10: You retrieve the submitted value by accessing the data at the key "follow" , which you defined in your template with the name HTML attribute on your <button> elements.
HttpResponse Methods – Django It is used to instantiate an HttpResponse object with the given page content and content type. HttpResponse.__setitem__(header, value) It is used to set the given header name to the given value.
Django uses request and response objects to pass state through the system. When a page is requested, Django creates an HttpRequest object that contains metadata about the request. Then Django loads the appropriate view, passing the HttpRequest as the first argument to the view function.
self. request = request is set in view function that as_view() returns. I looked into the history, but only found setting self. request and then immediately passing request into the view function.
You will need the {% csrf_token %} template tag in between your tags as well as including
django.middleware.csrf.CsrfViewMiddleware
django.middleware.csrf.CsrfResponseMiddleware
in your MIDDLEWARE_CLASSES in the applications settings.py
Adding some example post data handling:
This is an example of one of the times I am using POST data in a view. I will generally rely on the form class to do verification via the cleaned_data array.
if request.method == 'POST':
form = ForgotPassword(data=request.POST)
if form.is_valid():
try:
new_user = backend.forgot_password(request, **form.cleaned_data)
except IntegrityError:
context = {'form':form}
form._errors[''] = ErrorList(['It appears you have already requested a password reset, please \
check ' + request.POST['email2'] + ' for the reset link.'])
return render_template(request,'passwordReset/forgot_password.html',context)
if success_url is None:
to, args, kwargs = backend.post_forgot_password(request, new_user)
return redirect(to, *args, **kwargs)
else:
return redirect(success_url)
You've got to include {% csrf_token %}
in your form's template between your <form>
tags.
<form method="post" action"/wikicamp/{{page_name}}/save/">
{% csrf_token %}
<textarea name="content" rows="20" cols="60">{{content}}</textarea><br>
<input type="submit" value="Save Page"/>
</form>
If the csrf_token
is not rendered into your form make sure you're providing the RequestContext
in the view's response:
from django.shortcuts import render_to_response
from django.template import RequestContext
def app_view(request):
return render_to_response('app_template.html',
app_data_dictionary,
context_instance=RequestContext(request))
Or, use this shortcut method:
from django.views.generic.simple import direct_to_template
def app_view(request):
return direct_to_template(request, 'app_template.html', app_data_dictionary)
The RequestContext
is always available when you're using generic views.
I guess you've missed the symbol '=' in the form declaration.
action"/wikicamp/{{page_name}}/save/"
action="/wikicamp/{{page_name}}/save/"
Fortunately, it might be not a mistake. So if it is not a solution, try some more easy example:
# settings.py
TEMPLATE_DIRS = (
# Here comes something like "C:/www/django/templates"
)
MIDDLEWARE_CLASSES = (
...
'django.middleware.csrf.CsrfViewMiddleware',
...
)
# urls.py
urlpatterns = patterns('',
('^foo', foo),
)
# views.py
from django.http import HttpResponse
from django.shortcuts import render_to_response
from django.core.context_processors import csrf
def foo(request):
d = {}
d.update(csrf(request))
if 'output' in request.POST:
d.update({'output':request.POST['output']})
return render_to_response('foo.html',d)
# foo.html template
<html>
<h1> Foo </h1>
<form action="/foo" method = "post">
{% csrf_token %}
<input type="text" name="output"></input>
<input type="submit" value="go"></input>
</form>
<p> Output: {{ output }} </p>
</html>
Hope this will work
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With