I have looked at other similar problems on here and a few other places, but the solutions don't seem to help with my problem. Even though, I am not seeing too much of a difference between this simple code that I've got and other similar code. Especially this one Flask - wtforms: Validation always false
forms.validate_on_submit() is always false and I can't see why.
I'm going through the Flask Web Development Book by Miguel Grinberg, but I wanted to change some things in order to learn more.
It works when using the wtf.quick_form(form) in the html template, but if I remove the quickform entry and put in form fields , then it doesn't work
The screen just refreshes and it doesn't change Stranger to whatever name is entered
HTML index template
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Flasky{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>Hello, {% if name %}{{ name }}{% else %}Stranger{% endif %}!</h1>
</div>
<form action="" method='POST'>
{{ form.name.label }} <br>
{{ form.name }}
{{ form.submit }}
</form>
{% endblock %}
relevant code hello.py
from flask import Flask, render_template, request
from flask.ext.script import Manager
from flask.ext.bootstrap import Bootstrap
from flask.ext.moment import Moment
from flask.ext.wtf import Form
from wtforms import StringField, SubmitField, RadioField, TextField, validators
from wtforms.validators import Required
from wtforms.validators import DataRequired
app = Flask(__name__)
class NameForm(Form):
name = StringField('What is your name?',validators=[Required()] )
submit = SubmitField('Submit')
#app.route('/', methods=['GET', 'POST'])
def index():
name = None
form = NameForm(request.form) #From the docs I read I don't need
# request.form but it
# doesn't work either with it or without it
if form.validate() == True:
name='True' #never happens is not validating or is always set to False for
# some reason
if form.validate_on_submit(): #isn't validating or working
name = form.name.data #'Stranger' will disappear from the html template and
#replaced with the name the user entered in the
# Stringfield
form.name.data = '' #clear stringfield for next round
return render_template('index.html',form=form, name=name)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80, debug=True)'
what am I not understanding\missing?
Thanks
g
The problem is with wtf not finding the CSRF Tokens as part of your form data. Add {{ form.hidden_tag() }} or {{ form.csrf_token }} as the top element of your form.
Just a small remind for anyone who uses bootstrap template form like me.
Be sure to add "name" attribute into the input tag as well. For example,
<label>Your name</label>
<input name = 'name' required>
<label>Your email</label>
<input name = 'email' required>
Related
Using quick_form Flask-Bootstrap to generate the form is very convenient for me, however, I could not find in their documentation a way that I can add extras class to label as required by my template theme.
My forms.py class look like this:
from flask_wtf import Form
from wtforms import StringField,PasswordField,TextField,SubmitField
from wtforms.validators import InputRequired,EqualTo,Email,ValidationError
class Building_Form(Form):
BuildingName = TextField('Building Name')
BuildingType = TextField('Building Type')
FloorNums = TextField('Numers of Floor')
BuildUnits = TextField('Units in Building')
BuildSize = TextField('Building Size')
BuiltYear = TextField('Built in (year)')
BuildOpeningTime = TextField('Open Time')
BuildClosingTime = TextField('Close Time')
My routes.py is like following:
from app.import_core import *
from flask_wtf import FlaskForm
from wtforms import Form, BooleanField, StringField, PasswordField, validators
from wtforms.validators import DataRequired
from flask_wtf.file import FileField, FileRequired
from werkzeug.utils import secure_filename
from werkzeug.security import generate_password_hash, check_password_hash
from .forms import Building_Form
# from app.user.models import TBL_USER
import pdb
#app.route('/building')
def show_building_listing():
return render_template('building_listing.html')
#app.route('/builing/new',methods=['GET','POST'])
def add_new_builing():
form = Building_Form()
if request.method=='POST':
return '<h1>Ok Building added</h1>'
return render_template('new_building.html',form=form)
My new_building.html to render a form:
{% extends "__dashboard.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block include_css %}
<link rel="stylesheet" href="{{url_for('static',filename='css/login.css')}}">
<link rel="stylesheet" href="{{url_for('static',filename='css/bt-social-button/bootstrap-social.css')}}">
{% endblock %}
{% block content %}
<div class="card">
<div class="card-body">
{{ wtf.quick_form(form, extra_classes='bmd-label-floating') }}
</div>
</div>
{% endblock %}
I would like to add classes bmd-label-floating to my form label however it ended up with those classes in <form> instead.
How can I add that class my labels? Thanks.
I had a similar problem. A list of items was used to generate a form with multiple checkboxes. I needed to add a label class for styling them horizontally. I was able to loop through my form object and change class for the form field.label.
<form action="" method="post">
{% with test = form.example %}
{% for field in test %}
{{ field.label(class_='checkbox-inline') }}
{{ field }}
{% endfor %}
{% endwith %}
<p>{{ form.submit() }}</p>
</form>
how can i handle the request from listview template. if i click the submit button in my custom_list.html the the variables were not output as string. what did i do wrong ?
app.py
from flask import Flask
import flask_admin as admin
from flask_mongoengine import MongoEngine
from flask_admin.contrib.mongoengine import ModelView
from flask_admin.actions import action
# Create application
app = Flask(__name__)
# Create dummy secrey key so we can use sessions
app.config['SECRET_KEY'] = '123456790'
app.config['MONGODB_SETTINGS'] = {'DB': 'test_app'}
# Create models
db = MongoEngine()
db.init_app(app)
class Website(db.Document):
domain_name = db.StringField(max_length=200)
title = db.StringField(max_length=160)
meta_desc = db.StringField()
class WebsiteView(ModelView):
list_template = 'custom_list.html'
#action('create_meta', 'Create Meta', 'Are you sure you want to create meta data?')
def action_createmeta(self, ids):
print "this is my domain_name {} and this is my title {}".format(
Website.domain_name, Website.title)
# Flask views
#app.route('/')
def index():
return 'Click me to get to Admin!'
if __name__ == '__main__':
# Create admin
admin = admin.Admin(app, 'Example: MongoEngine')
# Add views
admin.add_view(WebsiteView(Website))
# Start app
app.run(debug=True)
templates/custom_list.html
{% extends 'admin/model/list.html' %}
{% block body %}
<h1>Custom List View</h1>
{{ super() }}
{% endblock %}
{% block list_row_actions %}
{{ super() }}
<form class="icon" method="POST" action="/admin/website/action/">
<input id="action" name="action" value="create_meta" type="hidden">
<input name="rowid" value="{{ get_pk_value(row) }}" type="hidden">
<button onclick="return confirm('Are you sure you want to create meta data?');" title="Create Meta">
<span class="fa fa-ok icon-ok"></span>
</button>
</form>
{% endblock %}
output
You are printing the definitions of Website.domain_name not the values.
From the documentation and example you need to do:
for id in ids:
found_object = Website.objects.get(id=id)
print "this is my domain_name {} and this is my title {}".format(
found_object.domain_name, found_object.title)
EDIT: original post.
Change the line
print "this is my domain_name {} and this is my title {}".format(
Website.domain_name, Website.title)
to
print "this is my domain_name {} and this is my title {}".format(
Website.domain_name.data, Website.title.data)
You are printing the objects not the posted data contained within them
I'm new to WTForms, and from what I've learned so far, I find the validation error handling a bit tricky.
First off, I can't implement the native HTML <input required >;
Secondly, when the form failed validation, I have to rerender the page template where the form is at, and if my form is placed on bottom of a page, the user will see the page 'refreshed' and have no idea what is going on.
Does anyone have suggestions on how to integrate WTForms more seamlessly? Any comments, resources, urls, code samples are welcomed, thanks!
Here are some of my related codes:
# /forms.py
from wtforms import Form, BooleanField, StringField, PasswordField, validators
class RegistrationForm(Form):
email = StringField('Email Address', [
validators.required(),
validators.Email(message='Please enter a valid email address'),
validators.length(min=6, max=35)
])
password = PasswordField('New Password', [
validators.required(),
validators.DataRequired(),
validators.length(min=6, max=35)
])
# /views.py
from flask import Flask, Blueprint, flash, render_template, redirect, request, url_for
from forms import RegistrationForm, LoginForm
app = Flask(__name__)
#app.route('/', methods=['GET', 'POST'])
def index():
form = RegistrationForm()
context = {
"form": form
}
if request.method == 'POST' and form.validate():
submitted_form = request.form
return redirect('/welcome')
else:
return render_template('form.html', context = context)
# /form.html
<form class="form" action="" method="POST" name="register">
{% for field_name, field_errors in context.reg_form.errors|dictsort if field_errors %}
{% for err in field_errors %}
<li class="error">{{ context.reg_form[field_name].label }}: {{ err }}</li>
{% endfor %}
{% endfor %}
<ul class="form-fields center">
<li class="form-field">
{{ context.form.email(class='email', placeholder='email') }}
</li>
<li class="form-field">
{{ context.form.password(class='password', placeholder='password') }}
</li>
</ul>
</form>
As far as I understand, WTForm will always have to refresh the page in order to show the errors. I worked this out is by letting the front-end to validate the form for me. Do not know if it possible on your case, but I've used AngularJS to do the trick. It's quite easy, not a single line of code is required if you need simple validation like email format, password length and etc, it's all done by html attributes. You can even disable the submit button until your form is ready to go.
Check out this CodePen
You can scroll to the bottom to the page using this, if still needed:
var objDiv = document.getElementById("your_div");
objDiv.scrollTop = objDiv.scrollHeight
If you need a more robust solution, you might come up with a API that return true or false to whatever field you want to validate. Then make angular make a http request to check it as you type, this way you are 100% sure you form is going to validate. But depending on what you are checking, you might expose a security hole. There is an excellent blog post about this on Ng-Newsletter
For a better experience with forms in Flask you should use the Flask-WTF extension. Install it:
$ pip install flask-wtf
import it
from flask.ext.wtf import Form
and use it along with wtforms module.
.py file:
from flask.ext.wtf import Form
from wtforms import StringField, SubmitField
from wtforms.validators import Required
class NameForm(Form):
name = StringField('What is your name?', validators=[Required()])
submit = SubmitField('Submit')
.html file:
<form method="POST">
{{ form.name.label }} {{ form.name() }}
{{ form.submit() }} #this is your submit button
</form>
I'm trying to render a template that contains a DatePicker, but I'm getting a 500 error when I try. For my the code is correct, but it seems that something is failing or I'm not understanding correctly the way to do it.
The code is the following:
Reporting.py
from flask.ext.admin import BaseView, expose
from wtforms import DateField, Form
from wtforms.validators import Required
from flask.ext.admin.form import widgets
from flask import request
class DateRangeForm(Form):
start_date = DateField('Start', validators=[Required()], format = '%d/%m/%Y', description = 'Time that the event will occur', widget=widgets.DatePickerWidget)
class ReportingView(BaseView):
#expose('/')
def index(self):
form = DateRangeForm(request.form)
return self.render('reporting.j2', form=form)
Reporting template:
{% extends 'admin/master.html' %}
{% block body %}
{{super()}}
Working on it!
{% if form %}
{{form.start_date}}
{% endif %}
{% endblock %}
As davidism says in the comments, the default DateField just provides date parsing, it'll just be displayed as a normal text-input.
If you're ready to fully embrace html5 then you can use the DateField from wtforms.fields.html5 which will render a datepicker in any browser that supports it:
from flask import Flask, render_template
from flask_wtf import Form
from wtforms.fields.html5 import DateField
app = Flask(__name__)
app.secret_key = 'SHH!'
class ExampleForm(Form):
dt = DateField('DatePicker', format='%Y-%m-%d')
#app.route('/', methods=['POST','GET'])
def hello_world():
form = ExampleForm()
if form.validate_on_submit():
return form.dt.data.strftime('%Y-%m-%d')
return render_template('example.html', form=form)
if __name__ == '__main__':
app.run(debug=True)
The more usual approach is to find a nice datepicker online, that's using CSS and JS to handle it's display and include that code into your html template, and tell it to apply the datepicker style to any html element that has a class of datepicker. Then when you generate your form you can just do:
<!-- all your CSS and JS code, including the stuff -->
<!-- to handle the datepicker formatting -->
<form action="#" method="post">
{{ form.dt(class='datepicker') }}
{{ form.hidden_tag() }}
<input type="submit"/>
</form>
Any attributes (that aren't reserved for other use) you pass into rendering the form element will by default just add it as an attribute, for example the {{ form.dt(class='datepicker') }} will generate <input class="datepicker" id="dt" name="dt" type="text" value=""> so your CSS/JS can then do whatever it needs to do to provide a good interface for your user.
I'm trying to build an app to upload a file to a web server using Flask and WTForms' FileField form field. The post is going through successfully but I am curious as to why form.validate_on_submit() fails each time even though the particular validators all succeed. Here is my code for the form (forms.py), the app (main.py) and the html template (upload.html).
### forms.py
from flask.ext.wtf import Form
from flask.ext.wtf.html5 import EmailField
from flask.ext.wtf.file import FileField, FileRequired, FileAllowed
from wtforms import validators, ValidationError, SubmitField
class UploadForm(Form):
presentation = FileField('Presentation in Image Format', validators=[FileRequired(), FileAllowed(['jpg', 'png'], 'Images only!')])
submit = SubmitField("Send")
### main.py
from forms import UploadForm
from flask import render_template, url_for, redirect, send_from_directory
#app.route('/upload/', methods=('GET', 'POST'))
def upload():
form = UploadForm()
if form.validate_on_submit():
filename = secure_filename(form.presentation.file.filename)
print filename
form.presentation.file.save(os.path.join('uploads/', filename))
return redirect(url_for('uploads', filename=filename))
filename = None
return render_template('upload.html', form=form, filename=filename)
#app.route('/uploads/<filename>')
def uploaded_file(filename):
return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
### upload.html
{% for message in form.presentation.errors %}
<div class="flash">{{ message }}</div>
{% endfor %}
<form action="/upload/" method="POST" enctype="multipart/form-data">
{{ form.presentation.label }}
{{ form.presentation }}
{{ form.submit}}
</form>
Does anyone know why this might not be validating? Or should I not be using validate_on_submit()?
Flask-WTF enables CRSF by default, if you print the form.errors, you will get a message that tells you a csrf token is required.
The solution is simple, put {{ form.csrf_token }} in your template, or disable CSRF of the form, but you really shouldn't do such thing.
<form action="/upload/" method="POST" enctype="multipart/form-data">
{{ form.presentation.label }}
{{ form.presentation }}
{{ form.csrf_token }}
{{ form.submit}}
</form>
There is also a quick way to add every hidden fields to the form hidden_tags:
<form action="/upload/" method="POST" enctype="multipart/form-data">
{{ form.presentation.label }}
{{ form.presentation }}
{{ form.hidden_tag() }}
{{ form.submit}}
</form>