См.также
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | from jinja2 import Template
from wtforms import BooleanField, Form, StringField, validators
class RegistrationForm(Form):
username = StringField('Username', [validators.Length(min=4, max=25)])
email = StringField('Email Address', [validators.Length(min=6, max=35)])
rules = BooleanField('I accept the site rules',
[validators.InputRequired()])
if __name__ == '__main__':
form = RegistrationForm(username="root")
template = Template("""
<form method="POST" action="">
{% for field in form.data %}
{{ form[field].label }} |
{{ form[field] }}
<br />
{% endfor %}
<input type="submit" value="Ok">
</form>
""")
print(template.render(form=form)) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <form method="POST" action="">
<label for="username">Username</label> |
<input id="username" name="username" type="text" value="root">
<br />
<label for="rules">I accept the site rules</label> |
<input id="rules" name="rules" type="checkbox" value="y">
<br />
<label for="email">Email Address</label> |
<input id="email" name="email" type="text" value="">
<br />
<input type="submit" value="Ok">
</form>
|
Deform — это Python библиотека для генерации форм. Deform использует Colander как генератор схемы, Peppercorn для десериализации данных из формы и шаблонизатор Chameleon.
Основные задачи, которые выполняет Deform:
Примеры форм http://deformdemo.repoze.org/
См.также
Colander - десериализует данные полученные как XML, JSON, HTTP POST запрос и проверяет правильность их заполнения по заранее заданной схеме.
Для создания простой формы нам понадобится:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | import colander
import deform
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates'))
class Contact(colander.MappingSchema):
email = colander.SchemaNode(colander.String(), validator=colander.Email())
name = colander.SchemaNode(colander.String())
message = colander.SchemaNode(colander.String(),
widget=deform.widget.TextAreaWidget())
def simple_form(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
from webob import Request
request = Request(environ)
form = deform.Form(Contact(), buttons=('submit',))
template = env.get_template('simple.html')
if request.POST:
submitted = request.POST.items()
try:
form.validate(submitted)
except deform.ValidationFailure as e:
return template.render(form=e.render())
data = {'email': 'jon.staley@fundingoptions.com',
'name': 'Jon',
'message': 'Hello World'}
return template.render(form=form.render(data))
if __name__ == '__main__':
from paste.httpserver import serve
serve(simple_form, host='0.0.0.0', port=8000) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | import colander
import deform
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates'))
class Contact(colander.MappingSchema):
email = colander.SchemaNode(colander.String(), validator=colander.Email())
name = colander.SchemaNode(colander.String())
message = colander.SchemaNode(colander.String(),
widget=deform.widget.TextAreaWidget())
def simple_form(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
from webob import Request
request = Request(environ)
form = deform.Form(Contact(), buttons=('submit',))
template = env.get_template('simple.html')
if request.POST:
submitted = request.POST.items()
try:
form.validate(submitted)
except deform.ValidationFailure as e:
return template.render(form=e.render())
data = {'email': 'jon.staley@fundingoptions.com',
'name': 'Jon',
'message': 'Hello World'}
return template.render(form=form.render(data))
if __name__ == '__main__':
from paste.httpserver import serve
serve(simple_form, host='0.0.0.0', port=8000) |
1 2 3 4 5 6 7 8 9 10 | <!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>simple</title>
</head>
<body>
{{ form }}
</body>
</html> |
Сгенерированная форма
Валидация формы
Добавим стилей:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | <!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>simple</title>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.96.1/css/materialize.min.css" />
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.96.1/js/materialize.min.js"></script>
<style type="text/css">
.deformFormFieldset {
border: none;
padding: 0;
margin: 0;
}
.control-label {
left: 0 !important;
}
.form-group
{
position: relative;
margin: 1em 0 0 0;
}
.alert-danger
{
top: -1.5em;
position: relative;
}
p.help-block[id*="error"]
{
width: 10em;
color: red !important;
font-style: normal;
padding: 0;
margin: 0 0 1em 0;
line-height: 1.5;
font-family: "Roboto", sans-serif;
font-weight: normal;
position: absolute;
left: -12em;
text-align: right;
top: 0.85em;
}
.required:after
{
content: "*";
position: relative;
font-family: "Roboto", sans-serif;
font-weight: normal;
color: red;
}
.errorMsgLbl
{
background: red;
font-family: "Roboto", sans-serif;
font-weight: normal;
padding: 0.5em 1em;
color: #fff;
margin: 0 0 1em 0;
}
.alert-danger .errorMsg
{
display: none;
}
</style>
</head>
<body>
<div class="form" style="width: 500px; margin: 0 auto; padding: 50px">
<h1>Simple Form</h1>
{{ form }}
</div>
</body>
<script type="text/javascript">
$(function() {
$('#item-deformField1').addClass('input-field').addClass('col');
$('#item-deformField2').addClass('input-field').addClass('col');
$('#item-deformField3').addClass('input-field').addClass('col');
$('#deformField3').addClass('materialize-textarea');
});
</script>
</html> |
Сгенерированная форма с применением CSS стилей
Валидация формы с применением CSS стилей
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | import colander
import deform
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates'))
class AddressSchema(colander.MappingSchema):
line1 = colander.SchemaNode(colander.String(), title='Address line 1')
line2 = colander.SchemaNode(colander.String(), title='Address line 2',
missing=None)
line3 = colander.SchemaNode(colander.String(), title='Address line 3',
missing=None)
town = colander.SchemaNode(colander.String(), title='Town')
postcode = colander.SchemaNode(colander.String(), title='Postcode')
class Business(AddressSchema):
business_name = colander.SchemaNode(colander.String(),
title='Business Name',
insert_before='line1')
def inheritance_form(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
from webob import Request
request = Request(environ)
form = deform.Form(Business(), buttons=('submit',))
template = env.get_template('simple_with_css.html')
if request.POST:
submitted = request.POST.items()
try:
form.validate(submitted)
except deform.ValidationFailure as e:
return template.render(form=e.render())
return template.render(form=form.render())
if __name__ == '__main__':
from paste.httpserver import serve
serve(inheritance_form, host='0.0.0.0', port=8000) |
Наследование Colander схемы
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | import colander
import deform
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates'))
def month_validator(node, month):
if month.isdigit():
int_month = int(month)
if not 0 < int_month < 13:
raise colander.Invalid(node,
'Please enter a number between 1 and 12')
else:
raise colander.Invalid(node, 'Please enter a number')
class AddressSchema(colander.MappingSchema):
line1 = colander.SchemaNode(colander.String(), title='Address line 1')
line2 = colander.SchemaNode(colander.String(), title='Address line 2',
missing=None)
line3 = colander.SchemaNode(colander.String(), title='Address line 3',
missing=None)
town = colander.SchemaNode(colander.String(), title='Town')
postcode = colander.SchemaNode(colander.String(), title='Postcode')
class Business(AddressSchema):
business_name = colander.SchemaNode(colander.String(),
title='Business Name',
insert_before='line1')
start_month = colander.SchemaNode(colander.String(), title='Start month',
validator=month_validator)
def custom_validator_form(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
from webob import Request
request = Request(environ)
form = deform.Form(Business(), buttons=('submit',))
template = env.get_template('simple_with_css.html')
if request.POST:
submitted = request.POST.items()
try:
form.validate(submitted)
except deform.ValidationFailure as e:
return template.render(form=e.render()).encode("utf-8")
return template.render(form=form.render()).encode("utf-8")
if __name__ == '__main__':
from paste.httpserver import serve
serve(custom_validator_form, host='0.0.0.0', port=8000) |
Кастомная валидация поля
См.также
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | import colander
import deform
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates'))
def get_session(request):
return request.environ.get('paste.session.factory', lambda: {})()
def get_csrf_token(session):
if 'csrf' not in session:
from uuid import uuid4
session['csrf'] = uuid4().hex
return session['csrf']
@colander.deferred
def deferred_csrf_default(node, kw):
request = kw.get('request')
session = get_session(request)
csrf_token = get_csrf_token(session)
return csrf_token
@colander.deferred
def deferred_csrf_validator(node, kw):
def validate_csrf_token(node, value):
request = kw.get('request')
session = get_session(request)
csrf_token = get_csrf_token(session)
if value != csrf_token:
raise colander.Invalid(node, 'Bad CSRF token')
return validate_csrf_token
class CSRFSchema(colander.Schema):
csrf = colander.SchemaNode(colander.String(),
default=deferred_csrf_default,
validator=deferred_csrf_validator,
# widget=deform.widget.HiddenWidget(), )
)
class Contact(CSRFSchema):
email = colander.SchemaNode(colander.String(), validator=colander.Email())
name = colander.SchemaNode(colander.String())
message = colander.SchemaNode(colander.String(),
widget=deform.widget.TextAreaWidget())
def custom_validator_form(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
from webob import Request
request = Request(environ)
session = get_session(request)
session['csrf'] = get_csrf_token(session)
schema = Contact().bind(request=request)
form = deform.Form(schema, buttons=('submit',))
template = env.get_template('simple_with_css.html')
if request.POST:
submitted = request.POST.items()
try:
form.validate(submitted)
except deform.ValidationFailure as e:
return template.render(form=e.render()).encode("utf-8")
session.pop('csrf')
return template.render(form='OK')
return template.render(form=form.render()).encode("utf-8")
if __name__ == '__main__':
from paste.httpserver import serve
from paste.session import SessionMiddleware
app = SessionMiddleware(custom_validator_form)
serve(app, host='0.0.0.0', port=8000) |
Ключ CSRF
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | import colander
import deform
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates'))
def get_session(request):
return request.environ.get('paste.session.factory', lambda: {})()
def get_csrf_token(session):
if 'csrf' not in session:
from uuid import uuid4
session['csrf'] = uuid4().hex
return session['csrf']
@colander.deferred
def deferred_csrf_default(node, kw):
request = kw.get('request')
session = get_session(request)
csrf_token = get_csrf_token(session)
return csrf_token
@colander.deferred
def deferred_csrf_validator(node, kw):
def validate_csrf_token(node, value):
request = kw.get('request')
session = get_session(request)
csrf_token = get_csrf_token(session)
if value != csrf_token:
raise colander.Invalid(node, 'Bad CSRF token')
return validate_csrf_token
class CSRFSchema(colander.Schema):
csrf = colander.SchemaNode(colander.String(),
default=deferred_csrf_default,
validator=deferred_csrf_validator,
# widget=deform.widget.HiddenWidget(), )
)
class Contact(CSRFSchema):
email = colander.SchemaNode(colander.String(), validator=colander.Email())
name = colander.SchemaNode(colander.String())
message = colander.SchemaNode(colander.String(),
widget=deform.widget.TextAreaWidget())
def custom_validator_form(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
from webob import Request
request = Request(environ)
session = get_session(request)
session['csrf'] = get_csrf_token(session)
schema = Contact().bind(request=request)
form = deform.Form(schema, buttons=('submit',))
template = env.get_template('simple_with_css.html')
if request.POST:
submitted = request.POST.items()
try:
form.validate(submitted)
except deform.ValidationFailure as e:
return template.render(form=e.render()).encode("utf-8")
session.pop('csrf')
return template.render(form='OK')
return template.render(form=form.render()).encode("utf-8")
if __name__ == '__main__':
from paste.httpserver import serve
from paste.session import SessionMiddleware
app = SessionMiddleware(custom_validator_form)
serve(app, host='0.0.0.0', port=8000) |
Ключ CSRF
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | import os
import colander
import deform
from jinja2 import Environment, FileSystemLoader
from pkg_resources import resource_filename
env = Environment(loader=FileSystemLoader('templates'))
deform_path = os.path.abspath('templates/deform')
deform_templates = resource_filename('deform', 'templates')
print(deform_templates)
print(deform_path)
search_path = (deform_path, deform_templates)
renderer = deform.ZPTRendererFactory(search_path)
class Contact(colander.MappingSchema):
email = colander.SchemaNode(colander.String(), validator=colander.Email())
name = colander.SchemaNode(colander.String())
message = colander.SchemaNode(colander.String(),
widget=deform.widget.TextAreaWidget())
def custom_template_form(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
from webob import Request
request = Request(environ)
form = deform.Form(Contact(), buttons=('submit',), renderer=renderer)
template = env.get_template('simple_with_css.html')
if request.POST:
submitted = request.POST.items()
try:
form.validate(submitted)
except deform.ValidationFailure as e:
return template.render(form=e.render()).encode("utf-8")
data = {'email': 'jon.staley@fundingoptions.com',
'name': 'Jon',
'message': 'Hello World'}
return template.render(form=form.render(data)).encode("utf-8")
if __name__ == '__main__':
from paste.httpserver import serve
serve(custom_template_form, host='0.0.0.0', port=8000) |
$ tree templates/deform/
templates/deform/
├── form.pt
└── mapping_item.pt
0 directories, 2 files
Переопределенный шаблон form.pt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | import os
import colander
import deform
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates'))
def jinja2_renderer(template_name, **kw):
kw['_'] = str # Hook for translation string with gettext
from jinja2 import Template
deform_jinja_path = os.path.abspath('templates/deform_jinja2')
jinja2_template = os.path.join(deform_jinja_path,
template_name + '.jinja2')
template = Template(open(jinja2_template).read())
return template.render(**kw)
class Contact(colander.MappingSchema):
email = colander.SchemaNode(colander.String(), validator=colander.Email())
name = colander.SchemaNode(colander.String())
message = colander.SchemaNode(colander.String(),
widget=deform.widget.TextAreaWidget())
def custom_template_form(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
from webob import Request
request = Request(environ)
form = deform.Form(Contact(), buttons=('submit',),
renderer=jinja2_renderer)
template = env.get_template('simple_with_css.html')
if request.POST:
submitted = request.POST.items()
try:
form.validate(submitted)
except deform.ValidationFailure as e:
return template.render(form=e.render()).encode("utf-8")
data = {'email': 'jon.staley@fundingoptions.com',
'name': 'Jon',
'message': 'Hello World'}
return template.render(form=form.render(data)).encode("utf-8")
if __name__ == '__main__':
from paste.httpserver import serve
serve(custom_template_form, host='0.0.0.0', port=8000) |
$ tree templates/deform_jinja2/
templates/deform_jinja2/
├── autocomplete_input.jinja2
├── checkbox_choice.jinja2
├── checkbox.jinja2
├── checked_input.jinja2
├── checked_password.jinja2
├── dateinput.jinja2
├── dateparts.jinja2
├── datetimeinput.jinja2
├── file_upload.jinja2
├── form.jinja2
├── hidden.jinja2
├── mapping_item.jinja2
├── mapping.jinja2
├── moneyinput.jinja2
├── password.jinja2
├── radio_choice.jinja2
├── readonly
│ ├── checkbox_choice.jinja2
│ ├── checkbox.jinja2
│ ├── checked_input.jinja2
│ ├── checked_password.jinja2
│ ├── dateparts.jinja2
│ ├── file_upload.jinja2
│ ├── form.jinja2
│ ├── mapping_item.jinja2
│ ├── mapping.jinja2
│ ├── password.jinja2
│ ├── radio_choice.jinja2
│ ├── richtext.jinja2
│ ├── select.jinja2
│ ├── sequence_item.jinja2
│ ├── sequence.jinja2
│ ├── textarea.jinja2
│ └── textinput.jinja2
├── richtext.jinja2
├── select.jinja2
├── sequence_item.jinja2
├── sequence.jinja2
├── textarea.jinja2
└── textinput.jinja2
1 directory, 39 files
1 2 3 4 5 6 7 8 9 10 11 12 | <textarea tal:define="rows rows|field.widget.rows;
cols cols|field.widget.cols;
css_class css_class|field.widget.css_class;
oid oid|field.oid;
name name|field.name;
style style|field.widget.style"
tal:attributes="rows rows;
cols cols;
class string: form-control ${css_class or ''};
style style"
id="${oid}"
name="${name}">${cstruct}</textarea> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <textarea
style="background: green;color:white;"
{% if field.widget.rows %}
rows="{{ field.widget.rows }}"
{% endif %}
{% if field.widget.cols %}
cols="{{ field.widget.cols }}"
{% endif %}
{% if field.widget.css_class %}
class="{{ field.widget.css_class }}"
{% endif %}
id="{{ field.oid }}"
name="{{ field.name }}"
{% if field.description %}
placeholder="{{ _(field.description) }}"
{% endif %}>{{ cstruct }}</textarea> |
Переопределенный шаблон textarea.jinja2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | import deform
import colander
from common import get_csrf_token, get_session
@colander.deferred
def deferred_csrf_default(node, kw):
request = kw.get('request')
session = get_session(request)
csrf_token = get_csrf_token(session)
return csrf_token
@colander.deferred
def deferred_csrf_validator(node, kw):
def validate_csrf_token(node, value):
request = kw.get('request')
session = get_session(request)
csrf_token = get_csrf_token(session)
if value != csrf_token:
raise colander.Invalid(node, 'Bad CSRF token')
return validate_csrf_token
class CSRFSchema(colander.Schema):
csrf = colander.SchemaNode(colander.String(),
default=deferred_csrf_default,
validator=deferred_csrf_validator,
widget=deform.widget.HiddenWidget(), )
class CreateArticle(CSRFSchema):
title = colander.SchemaNode(colander.String())
content = colander.SchemaNode(
colander.String(),
widget=deform.widget.TextAreaWidget(
css_class="blog-form-field__textarea")
) |
1 2 3 4 5 6 7 8 9 | def get_session(request):
return request.environ.get('paste.session.factory', lambda: {})()
def get_csrf_token(session):
if 'csrf' not in session:
from uuid import uuid4
session['csrf'] = uuid4().hex
return session['csrf'] |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | #! /usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2015 uralbash <root@uralbash.ru>
#
# Distributed under terms of the MIT license.
"""
Simple blog
"""
from paste.auth.basic import AuthBasicHandler
import selector
from views import BlogCreate, BlogDelete, BlogIndex, BlogRead, BlogUpdate
def authfunc(environ, username, password):
return username == 'admin' and password == '123'
def make_wsgi_app():
# BasicAuth applications
create = AuthBasicHandler(BlogCreate, 'www', authfunc)
update = AuthBasicHandler(BlogUpdate, 'www', authfunc)
delete = AuthBasicHandler(BlogDelete, 'www', authfunc)
# URL dispatching middleware
dispatch = selector.Selector()
dispatch.add('/', GET=BlogIndex)
dispatch.prefix = '/article'
dispatch.add('/add', GET=create, POST=create)
dispatch.add('/{id:digits}', GET=BlogRead)
dispatch.add('/{id:digits}/edit', GET=update, POST=update)
dispatch.add('/{id:digits}/delete', GET=delete)
# Static files
from paste.urlparser import StaticURLParser
static_app = StaticURLParser("static/")
from paste import urlmap
mapping = urlmap.URLMap()
mapping['/static'] = static_app
from paste.cascade import Cascade
app = Cascade([mapping, dispatch])
return app
if __name__ == '__main__':
from paste.httpserver import serve
from paste.session import SessionMiddleware
app = make_wsgi_app()
app = SessionMiddleware(app)
serve(app, host='0.0.0.0', port=8000) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | import deform
from jinja2 import Environment, FileSystemLoader
from webob import Request, Response
from common import get_csrf_token, get_session
from models import ARTICLES
env = Environment(loader=FileSystemLoader('templates'))
def wsgify(view):
def wrapped(environ, start_response):
request = Request(environ)
app = view(request).response()
return app(environ, start_response)
return wrapped
class BaseArticle(object):
def __init__(self, request):
self.request = request
article_id = self.request.environ['wsgiorg.routing_args'][1]['id']
(self.index,
self.article) = next(((i, art) for i, art in enumerate(ARTICLES)
if art['id'] == int(article_id)),
(None, None))
class BaseArticleForm(object):
def get_form(self):
from forms import CreateArticle
self.session = get_session(self.request)
self.session['csrf'] = get_csrf_token(self.session)
schema = CreateArticle().bind(request=self.request)
submit = deform.Button(name='submit',
css_class='blog-form__button')
self.form = deform.Form(schema, buttons=(submit,))
return self.form
@wsgify
class BlogIndex(object):
def __init__(self, request):
self.page = request.GET.get('page', '1')
from paginate import Page
self.paged_articles = Page(
ARTICLES,
page=self.page,
items_per_page=8,
)
def response(self):
return Response(env.get_template('index.html')
.render(articles=self.paged_articles))
@wsgify
class BlogCreate(BaseArticleForm):
def __init__(self, request):
self.request = request
def response(self):
if self.request.method == 'POST':
submitted = self.request.POST.items()
try:
self.get_form().validate(submitted)
except deform.ValidationFailure as e:
return Response(
env.get_template('create.html').render(form=e.render()))
max_id = max([art['id'] for art in ARTICLES])
ARTICLES.append(
{'id': max_id+1,
'title': self.request.POST['title'],
'content': self.request.POST['content']
}
)
self.session = get_session(self.request).pop('csrf')
return Response(status=302, location='/')
return Response(env.get_template('create.html')
.render(form=self.get_form().render()))
@wsgify
class BlogRead(BaseArticle):
def response(self):
if not self.article:
return Response(status=404)
return Response(env.get_template('read.html')
.render(article=self.article))
@wsgify
class BlogUpdate(BaseArticle, BaseArticleForm):
def response(self):
if self.request.method == 'POST':
submitted = self.request.POST.items()
try:
self.get_form().validate(submitted)
except deform.ValidationFailure as e:
return Response(
env.get_template('create.html').render(form=e.render()))
self.article['title'] = self.request.POST['title']
self.article['content'] = self.request.POST['content']
self.session = get_session(self.request).pop('csrf')
return Response(status=302, location='/')
return Response(
env.get_template('create.html')
.render(form=self.get_form().render(self.article)))
@wsgify
class BlogDelete(BaseArticle):
def response(self):
ARTICLES.pop(self.index)
return Response(status=302, location='/') |
1 2 3 4 5 6 7 8 9 10 11 12 13 | {% extends "base.html" %}
{% block title %}Create{% endblock %}
{% block content %}
<div class="blog__title">
<a href="/" class="blog__title-link">Simple Blog</a>
<span class="blog__title-text">Edit</span>
</div>
<form action="" method="POST" class="blog-form">
{{ form }}
</form>
{% endblock %} |
Теперь форма имеет валидацию, защиту от CSRF атак и генерируется автоматически при помощи Deform.
Валидация формы