I just started coding with Flask and I want to set up CSRF on a small form in my application. I am following this https://wtforms.readthedocs.io/en/stable/csrf.html for session based implementation. I looked around the web for a while for a solution to a similar problem but I had no success, apologies if this is a duplicate question.
Problem with this code:
When I run it in the virtual environment I get AttributeError: 'Request' object has no attribute 'POST'
-
Goal: implement csrf on wtform instance
Environment: wtf version 2.02, flask 0.10, venv with python 2.7
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)
The template is fci_form.html in the/templates folder
{% 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 %}
What am I missing here?