如何在Django 1.3中获取POST数据
嘿,我正在跟着一个教程学习用Django制作一个维基页面。不过,这个教程是基于Django 0.96的,而我用的是Django 1.3,所以有些地方不太一样。我已经自己解决了一些问题,但这个问题我就是搞不定。
我做了一个表单,用来提交数据到一个视图(view)。这是我的表单:
<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>
然后,/wikicamp/{{page_name}}/save/这个网址会重定向到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 + "/")
但是问题是我收到了这个错误:
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.
所以我查了一些文档,比如 http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#how-to-use-it。我试着按照上面的做法去操作,但还是出现了同样的错误。
所以:有没有人知道怎么在Django 1.3中正确处理表单提交的数据?
我觉得这可能和:视图函数使用了RequestContext来渲染模板,而不是Context有关,但我不知道这是什么。
顺便说一下,在我的终端中显示本地请求时,它说:模板中使用了{% csrf_token %},但上下文没有提供值。这通常是因为没有使用RequestContext造成的。
4 个回答
我想你可能在表单声明中漏掉了符号 '='。
action"/wikicamp/{{page_name}}/save/"
action="/wikicamp/{{page_name}}/save/"
幸运的是,这可能并不是一个错误。
所以如果这个不是解决办法,可以试试一些更简单的例子:
# 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>
希望这个能奏效。
你需要在表单的模板中,在<form>
标签之间加入{% 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>
如果你的表单中没有显示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))
或者,你可以使用这个快捷方法:
from django.views.generic.simple import direct_to_template
def app_view(request):
return direct_to_template(request, 'app_template.html', app_data_dictionary)
当你使用通用视图时,RequestContext
总是可以用的。
你需要在你的标签之间加上 {% csrf_token %} 这个模板标签,同时还要在你的应用的 settings.py 文件中的
django.middleware.csrf.CsrfViewMiddleware
django.middleware.csrf.CsrfResponseMiddleware
的 MIDDLEWARE_CLASSES 部分包含它。
下面是一些处理 POST 数据的示例:
这是我在一个视图中使用 POST 数据的一个例子。通常我会依赖表单类通过 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)