Skip to content

Instantly share code, notes, and snippets.

@molszewski
Created February 3, 2014 11:40
Show Gist options
  • Save molszewski/8782476 to your computer and use it in GitHub Desktop.
Save molszewski/8782476 to your computer and use it in GitHub Desktop.
#!venv/bin/python
# Requirements:
# - virtualenv in venv dir (virtualenv venv)
# - Flask: venv/bin/pip install flask
# - formencode: venv/bin/pip install formencode
# - FormEncode-Jinja2: venv/bin/pip install FormEncode-Jinja2
from flask import render_template_string, flash, redirect, request
from formencode import Invalid, variabledecode, Schema, All
from formencode.validators import Int, UnicodeString, FancyValidator, MinLength
from formencode.schema import SimpleFormValidator
from datetime import date
from flask import Flask
import formencode_jinja2
##############################################################
# App configuration
app = Flask(__name__)
app.jinja_env.add_extension(formencode_jinja2.formfill)
app.config.update(
DEBUG=True,
SECRET_KEY='so key much secret'
)
##############################################################
# Validation schemas
MONTH_OPTIONS = (
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
)
class MonthValidator(FancyValidator):
def _to_python(self, value, state):
return value.strip()
def validate_python(self, value, state):
if value not in MONTH_OPTIONS:
raise Invalid('Invalid month name. Valid are ' + ', '.join(MONTH_OPTIONS), value, state)
return value
def validate_date_of_birth(value_dict, state, validator):
day = value_dict['day']
month = value_dict['month']
year = value_dict['year']
numeric_month = MONTH_OPTIONS.index(month)
try:
parsed_date = date(year, numeric_month + 1, day)
except:
raise Invalid('Date is invalid!', value_dict, state)
if parsed_date.year < 1900 or parsed_date >= date.today():
raise Invalid('Date < 1900 or in future', value_dict, state)
return None
class DateOfBirth(Schema):
day = Int(not_empty=True, strip=True)
month = MonthValidator(not_empty=True, strip=True)
year = Int(not_empty=True, strip=True)
chained_validators = [
SimpleFormValidator(validate_date_of_birth)
]
class Registration(Schema):
username = All(MinLength(10), UnicodeString(not_empty=True, strip=True))
dob = DateOfBirth()
##############################################################
# Template
REGISTRATION_TEMPLATE = '''
<html>
<head>
<title>formencode Spike</title>
</head>
<body>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }} </li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
<h1>Register</h1>
<div>
{{debug_info}}
</div>
<form action="" method="post" name="login">
<p>Dude, please register:</p>
<p>
{%- formfill form_data with errors -%}
<span>Name</span><input type="text" name="username"/><form:error name="username" /><br/>
<span>DOB</span>
<form:iferror name="dob"><span style="color:red">Start of DOB error [[[</form:iferror>
<input type="number" name="dob.day"/><form:error name="dob.day" />
<input type="text" name="dob.month"/><form:error name="dob.month" />
<input type="number" name="dob.year"/><form:error name="dob.year" />
<form:error name="dob" />
<form:iferror name="dob">]]] End of DOB error</span></form:iferror>
{%- endformfill -%}
</p>
<p><input type="submit" value="Hit me, pal"></p>
</form>
</body>
</html>
'''
INDEX_TEMPLATE='''
<html>
<head>
<title>formencode Spike</title>
</head>
<body>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }} </li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
<h1>Hello, please <a href="/register">register here</a></h1>
</body>
</html>
'''
##############################################################
# App routes
@app.route('/')
@app.route('/index')
def index():
return render_template_string(INDEX_TEMPLATE)
@app.route('/register', methods=['GET', 'POST'])
def schema():
schema = Registration()
form_data = request.form
if form_data:
try:
decoded = variabledecode.variable_decode(form_data)
result = schema.to_python(decoded)
flash('Submitted ' + str(variabledecode.variable_encode(result)))
return redirect('/index')
except Invalid, e:
unpacked_errors = e.unpack_errors(variabledecode.variable_encode)
return render_template_string(REGISTRATION_TEMPLATE,
title='Register',
form_data=form_data,
errors=unpacked_errors)
else:
return render_template_string(REGISTRATION_TEMPLATE,
title='Register',
form_data=form_data)
##############################################################
# App start
app.run(debug=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment