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.
嘿,我正在跟随本教程学习如何用Django创建一个wiki页面。但是,它是在django 0.96中生成的,我使用django 1.3,所以有些东西是不同的。有些我已经修好了,但是这个我似乎不能让它工作。
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:
和/wikicamp/{{page_name} /save/ url重定向到save_page视图:
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.
所以我通读了一些文档,比如http://docs.djangoproject.com/en/dev/ref/后悔/csrf/#how-to- it。我试着这么做,但还是有同样的错误。
So: Anyone an idea how to handle form post data well with Django 1.3?
那么:有谁知道如何用Django 1.3很好地处理表单post数据吗?
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.
我认为它与以下内容有关:视图函数使用RequestContext作为模板,而不是上下文。但我现在不知道是什么。
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.
在我的终端中,它显示了本地主机的http请求,它说:{% csrf_token %}在模板中使用,但是上下文没有提供该值。这通常是由于不使用RequestContext引起的。
4 个解决方案
#1
9
You will need the {% csrf_token %} template tag in between your tags as well as including
您将需要在标记之间加上{% csrf_token %}模板标记以及include
django.middleware.csrf.CsrfViewMiddleware
django.middleware.csrf.CsrfResponseMiddleware
in your MIDDLEWARE_CLASSES in the applications settings.py
在应用程序的settings.y中
Adding some example post data handling:
添加一些示例post数据处理:
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.
这是我在视图中使用POST数据的一个例子。我通常会依赖form类通过cleaned_data数组进行验证。
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)
#2
9
You've got to include {% csrf_token %}
in your form's template between your <form>
tags.
您必须在窗体的模板中包含{% csrf_token %},位于
<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:
如果csrf_token没有呈现到表单中,请确保您在视图的响应中提供了RequestContext:
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.
在使用泛型视图时,RequestContext总是可用的。
#3
2
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
希望这将工作
#4
2
re above use "request.POST" not "c.POST" in the 3rd line
以上使用“请求。“不是“c。贴在第三行
def save_page (request,page_name):
content = request.POST["content"]
and change in "edit_page"
在“edit_page”和改变
- return render_to_response("edit.html",{"page_name":page_name, "content":content})
+ t = get_template('edit.html')
+ html = t.render(Context({"page_name":page_name, "content":content}))
+ return HttpResponse(html)
- :remove
+ :add
#1
9
You will need the {% csrf_token %} template tag in between your tags as well as including
您将需要在标记之间加上{% csrf_token %}模板标记以及include
django.middleware.csrf.CsrfViewMiddleware
django.middleware.csrf.CsrfResponseMiddleware
in your MIDDLEWARE_CLASSES in the applications settings.py
在应用程序的settings.y中
Adding some example post data handling:
添加一些示例post数据处理:
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.
这是我在视图中使用POST数据的一个例子。我通常会依赖form类通过cleaned_data数组进行验证。
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)
#2
9
You've got to include {% csrf_token %}
in your form's template between your <form>
tags.
您必须在窗体的模板中包含{% csrf_token %},位于
<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:
如果csrf_token没有呈现到表单中,请确保您在视图的响应中提供了RequestContext:
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.
在使用泛型视图时,RequestContext总是可用的。
#3
2
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
希望这将工作
#4
2
re above use "request.POST" not "c.POST" in the 3rd line
以上使用“请求。“不是“c。贴在第三行
def save_page (request,page_name):
content = request.POST["content"]
and change in "edit_page"
在“edit_page”和改变
- return render_to_response("edit.html",{"page_name":page_name, "content":content})
+ t = get_template('edit.html')
+ html = t.render(Context({"page_name":page_name, "content":content}))
+ return HttpResponse(html)
- :remove
+ :add