【问题标题】:how to get POST data in django 1.3如何在 django 1.3 中获取 POST 数据
【发布时间】:2011-08-26 15:05:41
【问题描述】:

嘿,我正在按照本教程学习使用 Django 制作 wiki 页面。但是,它是在 django 0.96 中制作的,而我使用的是 Django 1.3,所以有些东西是不同的。有些我自己已经修好了,但是这个我似乎无法让它工作。

我制作了一个向视图提交数据的表单。 这是表格:

<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/ 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 + "/")

但是问题是我得到了这个错误:

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。但我现在不知道它是什么。

顺便说一句,在我的终端中,它显示了本地主机的 http 请求,它说:在模板中使用了 {% csrf_token %},但上下文没有提供值。这通常是由于没有使用 RequestContext 造成的。

【问题讨论】:

    标签: python django http-post django-1.3


    【解决方案1】:

    您需要在标签之间加上 {% csrf_token %} 模板标签,并包括

       django.middleware.csrf.CsrfViewMiddleware
       django.middleware.csrf.CsrfResponseMiddleware
    

    在应用程序 settings.py 中的 MIDDLEWARE_CLASSES 中

    添加一些示例帖子数据处理:

    这是我在视图中使用 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)
    

    【讨论】:

    • 如果我添加了那个并单击表单按钮不会发生错误,但表单页面只是重新加载清空 textarea 字段而没有任何反应。 (反正不是我想要的重定向)
    • 我用 c.update(csrf(request)) content = c.POST["content"] 更新了我在问题中的观点,这样可以吗?
    • 调试是否开启?如果可以,您可以发布堆栈跟踪吗?
    • 我不相信你一定要使用令牌,几个月前我从 1.1 升级到 1.3 时遇到了这个问题,我所要做的就是添加中间件条目和 csrf_token
    • 我用整个错误更新了我的 wuestion。如果这不是堆栈跟踪,请解释我如何获得它。谢谢!
    【解决方案2】:

    您必须在表单模板中的&lt;form&gt; 标记之间包含{% 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 令牌是否实际呈现在表单中。
    • 仔细看看,你的MIDDLEWARE_CLASSES 中的settings.py 中是否有django.middleware.csrf.CsrfViewMiddleware
    • 是的,我做到了,csrf 令牌未在表单中呈现。但是包含那个令牌怎么可能解决我所有的 CSRF 问题呢?
    • 您也可以尝试删除您的 cookie。
    【解决方案3】:

    我猜你错过了表单声明中的符号“=”。

    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>
    

    希望这会奏效

    【讨论】:

      【解决方案4】:

      上面在第三行使用“request.POST”而不是“c.POST”

      def save_page (request,page_name):
          content = request.POST["content"]
      

      并更改“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
      

      【讨论】:

        猜你喜欢
        • 2023-04-06
        • 2020-08-29
        • 2016-03-09
        • 1970-01-01
        • 2011-08-14
        • 1970-01-01
        • 2013-07-23
        • 2014-04-26
        • 1970-01-01
        相关资源
        最近更新 更多