Flask wtf表单AttributeError:' Request'对象没有属性' POST'

时间:2015-04-07 21:35:20

标签: python session flask flask-wtforms

我刚刚开始使用Flask进行编码,我想在我的应用程序中的小表单上设置CSRF。我正在关注此http://wtforms.readthedocs.org/en/2.0.2/csrf.html以进行基于会话的实施。我在网上浏览了一段时间以找到类似问题的解决方案,但我没有成功,如果这是一个重复的问题,请道歉。

此代码出现问题: 当我在虚拟环境中运行它时,我会使用AttributeError: 'Request' object has no attribute 'POST' -

获得以下堆栈跟踪

目标:在wtform实例上实现csrf

环境:wtf版本2.02,烧瓶0.10,venv with python 2.7

    Traceback (most recent call last):
  File "/home/maria/Desktop/ciacicode/fci/venv/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/maria/Desktop/ciacicode/fci/venv/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/home/maria/Desktop/ciacicode/fci/venv/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/maria/Desktop/ciacicode/fci/venv/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/maria/Desktop/ciacicode/fci/venv/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/maria/Desktop/ciacicode/fci/venv/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/maria/Desktop/ciacicode/fci/venv/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/maria/Desktop/ciacicode/fci/venv/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
TypeError: fci_form() takes exactly 1 argument (0 given)

fci_form.py

from flask import session, request
from flask.ext.wtf import Form
from wtforms import TextField, validators, SubmitField
from wtforms.validators import Required, Length
from wtforms.csrf.session import SessionCSRF
from datetime import timedelta
import config # my config file

# create super class

class MyForm(Form):
    class Meta:
        csrf = True
        csrf_class = SessionCSRF
        csrf_secret = config.secret_key
        csrf_time_limit = timedelta(minutes=20)

        @property
            def csrf_context(self):
                return request.session


# create a class for the form
class postcodeInput(MyForm):
    postcode = TextField('postcode',[validators.Required(message=(u"Where is your postcode?")),validators.Length(min=2, max=10)])
    submit = SubmitField('Submit')

views.py

from flask import Flask, render_template, request, __version__, url_for, session, abort, flash, redirect
# importing the class called postcode_input
from fci_form import postcodeInput
import config
import fciUtils

#pdb.set_trace()
app = Flask(__name__)
app.debug = True

# Views of the app

@app.route('/')
def index():
  return render_template('home.html')


@app.route('/fci', methods=['GET', 'POST'])
def fci_form():
    error = None
    form = postcodeInput(request.POST, meta={'csrf_context': request.session})
    if form.validate_on_submit():
            # handle user input
            postcode = request.form['postcode']
            # calculate fci
            result = fciUtils.fciReturn(postcode)
            return render_template('fci_form.html',form = form, result = result)
    elif request.method == 'GET':
        return render_template('fci_form.html', form = form)
    else:
        error = 'Enter a valid postcode'
        return render_template('fci_form.html', form=form, error=error)



if __name__ == '__main__':
    app.secret_key = config.secret_key
    app.run(threaded=True)

/ templates文件夹

中的模板是 fci_form.html
{% extends 'layout.html' %}
{% block form %}
<section>
    <header><h1>...</h1><br></header>
    <form action="{{ url_for('fci_form')}}" method='POST'>
        <p>Enter your London postcode:</p>
        <section>
            {% if error %}
            <p class="error"><strong>Error: </strong>{{error}}</p>
            {% endif %}
            {{form.csrf_token}}
            {{form.postcode}}
            {{form.submit(class_="pure-button")}}   
        </section>
    </form> 
</section> 

{% endblock %}

{% block result %}

    <section>
        <h4>{{result}}</h4> 
    </section>

{% endblock %}

我在这里缺少什么?

2 个答案:

答案 0 :(得分:2)

github README进入WTForms项目:

  

WTForms是一个灵活的表单验证和呈现库,用于   Python Web开发。 与框架无关,并且可以与   您选择的任何Web框架和模板引擎。

..强调我的。与框架无关的意思是,这不仅是Flask的库,还包括诸如此类的示例(来自https://wtforms.readthedocs.io/en/stable/csrf.html#using-csrf):

def view():
    form = UserForm(request.POST)
    if request.POST and form.validate():
        pass # Form is valid and CSRF succeeded

    return render('user.html', form=form)

...不一定是任何网络框架中的工作模式,而只是展示该库工作方式的一般说明。

该示例转换为Flask特定示例可能看起来像这样:

@app.route('/submit', methods=("GET", "POST"))
def submit():
    form = UserForm(request.form)
    if request.method == "POST" and form.validate():
        pass  # Form is valid and CSRF succeeded
    return render_template('submit.html', form=form)

自述文件继续说:

  

有许多社区库可以与   流行的框架。

一个这样的示例是Flask-WTF,其围绕WTForms的库的“ hello world”如下所示:

@app.route('/submit', methods=('GET', 'POST'))
def submit():
    form = MyForm()
    if form.validate_on_submit():
        return redirect('/success')
    return render_template('submit.html', form=form)

请注意,request.form不必像原始WTForms示例(MyForm)那样传递给UserForm(request.form)构造函数,并且在名为validate_on_submit()的表单,它既测试请求是一个POST请求,又测试提交的表单内容是否通过了验证。

POST可以更轻松地处理将Flask-WTF数据传递到表单和进行验证的过程,还简化了CSRF令牌管理,可以了解here

答案 1 :(得分:0)

您的问题是您将/fci路线定义为:

def fci_form(request):

表示您希望传递参数。但是,Flask不通过函数参数传递request,而是提供a thread-local request object。只需删除参数,然后从request导入flask

from flask import request

# and then later
def fci_form():