jinja2 templates - san francisco flask meetup
TRANSCRIPT
Flask Templates(aka Jinja2)
by @alanhamlett
Blocks ( templates/common/base.html )
Blocks name parts of your template, and can be re-used in child templates.
<html>
<title>{% block title %}My Website{% endblock %}</title>
<body>
{% block body %}
{% endblock %}
</body>
</html>
Inheritance ( templates/login.html )
{% extends "common/base.html" %}
{% block title %}super() - Login{% endblock %}
{% block body %}
<form method="POST">
<p><input type="text" name="username" /></p>
<p><input type="password" name="password" /></p>
<p><button type="submit">Login</button></p>
</form>
{% endblock %}
Variable Scope ( templates/common/base.html )
<html>
<title>{% block title %}My Website{% endblock %}</title>
<body>
{% with %}
{% set variable = "value" %}
{% block body %}
{% endblock %}
{% endwith %}
</body>
</html>
Variable Scope ( templates/login.html )
{% extends "common/base.html" %}
{% block title %}super() - Login{% endblock %}
{% block body %}
<form method="POST">
<p><input type="hidden" name="variable" value="{{variable}}" /></p>
<p><input type="text" name="username" /></p>
<p><input type="password" name="password" /></p>
<p><button type="submit">Login</button></p>
</form>
{% endblock %}
Rendering Templates ( __init__.py )
from flask import Flask
app = Flask(__name__)
from flask import render_template
@app.route("/login")
def login():
return render_template('login.html')
if __name__ == "__main__":
app.run()
Rendering Templates ( __init__.py )
from flask import Flask
app = Flask(__name__)
from . import views
if __name__ == "__main__":
app.run()
Rendering Templates ( views.py )
from . import app
from flask import render_template
@app.route("/login")
def login():
context = {
'features': [
{'icon': 'free.png', 'name': 'Free'},
{'icon': 'easy.png', 'name': 'Easy'},
{'icon': 'powerful.png', 'name': 'Powerful'},
],
}
return render_template('login.html', **context)
Rendering Variables ( templates/login.html )
{% extends "common/base.html" %}
{% block title %}super() - Login{% endblock %}
{% block body %}
<h1>Included Features:</h1>
<ul>
{% for feature in features %}
<li><img src="{{STATIC_URL}}img/icons/{{feature.icon}}" /> {{feature.name}}</li>
{% endfor %}
</ul>
<form method="POST">
<p><input type="text" name="username" /></p>
<p><input type="password" name="password" /></p>
<p><button type="submit">Login</button></p>
</form>
{% endblock %}
Filters ( templates/login.html )
{% extends "common/base.html" %}
{% block title %}super() - Login{% endblock %}
{% block body %}
<h1>Included Features:</h1>
<ul>
{% for feature in features %}
<li><img src="{{STATIC_URL}}img/icons/{{feature.icon}}" /> {{feature.name|lower}}</li>
{% endfor %}
</ul>
<form method="POST">
<p><input type="text" name="username" /></p>
<p><input type="password" name="password" /></p>
<p><button type="submit">Login</button></p>
</form>
{% endblock %}
Flask-WTF ( forms.py )
from flask.ext.wtf import Form
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired, Email, Length
class LoginForm(Form):
username = StringField('name', validators=[DataRequired(), Email()])
username = PasswordField('name', validators=[DataRequired(), Length(min=6)])
Flask-WTF ( views.py )
from . import app
from .forms import LoginForm
from flask import render_template, request
@app.route("/login", methods=('GET', 'POST'))
def login():
form = LoginForm(request.form)
if request.method == 'POST' and form.validate():
return redirect('/myprofile')
return render_template('login.html', form=form)
Flask-WTF ( templates/login.html )
{% extends "common/base.html" %}
{% block title %}super() - Login{% endblock %}
{% block body %}
<form method="POST">
<p>Username <input type="text" name="username" value="{{form.data.username or ''}}" /></p>
<p>Password <input type="password" name="password" value="{{form.data.password or ''}}" /></p>
<p><button type="submit">Login</button></p>
</form>
{% endblock %}
Flask-WTF ( templates/login.html )...
{% block body %}
<form method="POST">
{% for field in form._fields.values() %}
< div class="form-group" >
{{ field.label(class="col-sm-3 control-label") }}
< div class="col-sm-6 col-md-4" >
{{ field(class="form-control") }}
{% for error in field.errors %}
< p>{{error}}</ p>
{% endfor %}
</ div>
</ div>
{% endfor %}
<div class="form-group" >
< div class="col-sm-6 col-md-4 col-sm-offset-3" >
< button type="submit">Login</button>
</ div>
</ div>
</form>
{% endblock %}
...
Flask-Admin
Flask-Admin ( admin.py )from . import app
from .models import db, User
from flask.ext.admin import Admin
from flask.ext.admin.contrib.sqla import ModelView
admin = Admin(app)
admin.add_view(ModelView(User, db.session))
Flask-Admin ( __init__.py )from flask import Flask
app = Flask(__name__)
from . import views
from . import admin
if __name__ == "__main__":
app.run()
Flask-Admin
Extend these Flask-Admin classes to protect your Admin pages:
● flask.ext.admin.AdminIndexView
● sqla.ModelView
Flask-Admin ( admin.py )from . import app
from .models import db, User
from flask.ext.admin import Admin, AdminIndexView as UnsafeAdminIndexView, expose
from flask.ext.admin.contrib.sqla import ModelView
class AdminIndexView(UnsafeAdminIndexView):
@expose('/')
def index(self):
if not app.current_user.is_authenticated():
return redirect('/login')
if not app.current_user.is_admin:
abort(403)
return super(AdminIndexView, self).index()
@expose('/login/')
def login_view(self):
return redirect('/login')
@expose('/logout/')
def logout_view(self):
return redirect('/logout')
admin = Admin(app, index_view=AdminIndexView(), template_mode='bootstrap3', base_template='admin/custom_base.html')
admin.add_view(ModelView(User, db.session))
Flask-Admin ( admin.py )...
class ModelView(sqla.ModelView):
edit_template = 'admin/model/edit.html'
create_template = 'admin/model/create.html'
list_template = 'admin/model/custom_list.html'
def __init__(self, *args, **kwargs):
if 'exclude' in kwargs:
self.form_excluded_columns = kwargs['exclude']
del kwargs['exclude']
if 'show' in kwargs:
self.column_list = kwargs['show']
del kwargs['show']
pass_through = [
'can_create',
'can_edit',
'can_delete',
]
for item in pass_through:
if item in kwargs:
setattr(self, item, kwargs[item])
del kwargs[item]
super(ModelView, self).__init__(*args, **kwargs)
def is_accessible(self):
return app.current_user.is_authenticated() and app.current_user.is_admin
admin.add_view(ModelView(User, db.session, category='Users', exclude=['password', 'heartbeats'], can_delete=False))
...
Now go build something cool!
Alan Hamlett@alanhamlett on Twitter & GitHub
View this online at
http://slidesha.re/1wfDzrv