36
If you’ve beenfollowing alongin thistutorial,you mightbe wonderingwhere toput
the code from this step and the next. A logical place is to group these module-level
functions together, and put your new before_request and teardown_request func-
tionsbelow yourexistinginit_dbfunction(followingthe tutorial line-by-line).
If you needa moment to find your bearings, take a look at how theexamplesource
isorganized. In Flask, you can put all of your application code into a single Python
module. You don’thave to,andif yourappgrowslarger,it’sagoodideanotto.
5.7 Step 5: The View Functions
Now that the database connections are working we can start writing the view func-
tions. We will needfourofthem:
5.7.1 Show Entries
This view shows all the entries stored in the database. It listens on the root of the
application and will select title and text from the database. The one with the highest
id (the newest entry) will be on top. The rows returned from the cursor are tuples
with the columns orderedlike specifiedin the select statement. Thisis goodenough
forsmall applicationslikehere,butyou mightwanttoconvertthemintoadict. If you
are interestedinhowtodothat,checkoutthe EasyQueryingexample.
The view function will pass the entries asdictstothe show_entries.html template and
returnthe renderedone:
@app.route(/)
def show_entries():
cur = g.db.execute(select title, text t from m entries order r by id desc)
entries = [dict(title=row[0], text=row[1]) ) for row in cur.fetchall()]
return render_template(show_entries.html, entries=entries)
5.7.2 Add New Entry
This view lets the user add new entries if they are logged in. This only responds
to POST requests, the actual form is shown on the show_entries page. If everything
workedoutwellwewillflash()aninformationmessagetothe nextrequestandredi-
rectbacktothe show_entriespage:
@app.route(/add, methods=[POST])
def add_entry():
if not t session.get(logged_in):
abort(401)
g.db.execute(insert into o entries (title, , text) ) values (?, ?),
[request.form[title], request.form[text]])
33
How to C#: Basic SDK Concept of XDoc.Word Conversely, conversion from PDF to Word (.docx) is also supported. methods and events necessary to load a Word document from file or query data and save the
save data in pdf form reader; make pdf form editable in reader
40
g.db.commit()
flash(New entry y was successfully y posted)
return redirect(url_for(show_entries))
Note that we check that the user is loggedinhere (the logged_inkeyispresent in the
session andTrue).
SecurityNote
BesuretousequestionmarkswhenbuildingSQLstatements,asdone inthe example
above. Otherwise, your app will be vulnerable toSQLinjection when you use string
formattingtobuildSQLstatements. See UsingSQLite 3withFlaskfor more.
5.7.3 Login and Logout
These functionsare usedto sign the user in and out. Loginchecksthe username and
passwordagainsttheonesfromthe configurationandsetsthe logged_inkeyintheses-
sion. Iftheuserloggedinsuccessfully,thatkeyissettoTrue,andtheuserisredirected
backtothe show_entriespage. Inaddition, a message isflashed that informs the user
that he or shewasloggedinsuccessfully. If anerroroccurred,thetemplateisnotified
aboutthat,andthe userisaskedagain:
@app.route(/login, methods=[GET, POST])
def login():
error = None
if request.method == POST:
if request.form[username] != app.config[USERNAME]:
error = Invalid username
elif request.form[password] != app.config[PASSWORD]:
error = Invalid password
else:
session[logged_in] = True
flash(You were e logged in)
return redirect(url_for(show_entries))
return render_template(login.html, error=error)
The logoutfunction, onthe otherhand,removes that keyfrom the session again. We
use aneattrickhere: ifyouusethepop()methodofthe dictandpassasecondparam-
eter toit (the default),the methodwill deletethekeyfromthe dictionaryif present or
donothing when that keyisnot inthere. Thisishelpful because now we don’t have
tocheckif the userwasloggedin.
@app.route(/logout)
def logout():
session.pop(logged_in, None)
flash(You were logged out)
return redirect(url_for(show_entries))
34
37
Continue withStep6: TheTemplates.
5.8 Step 6: The Templates
Nowweshouldstartworkingonthetemplates. IfwerequesttheURLsnowwewould
only get an exception that Flask cannot find the templates. The templates are using
Jinja2syntaxandhaveautoescapingenabledbydefault. Thismeansthatunlessyou
markavalueinthecodewithMarkuporwiththe|safefilterinthetemplate,Jinja2will
ensure that special characterssuchas<or >areescapedwiththeirXMLequivalents.
We are alsousingtemplate inheritance which makes it possible toreuse the layout of
the website inallpages.
Putthe followingtemplatesintothetemplatesfolder:
5.8.1 layout.html
Thistemplate containsthe HTMLskeleton, the header anda linktologin(or logout
if the user was already logged in). It also displays the flashed messages if there are
any. The {% block body %}block canbe replacedbyablockof the same name (body)
inachildtemplate.
The session dict is available in the template as well and you can use that to check
if the user is logged in or not. Note that in Jinja you can access missing attributes
anditemsofobjects / dictswhichmakesthe following code work, even if there isno
’logged_in’keyinthe session:
<!doctype html>
<title>Flaskr</title>
<link rel=stylesheet type=text/css href="{{ url_for(static, filename=style.css) }}">
<div class=page>
<h1>Flaskr</h1>
<div class=metanav>
{% if not session.logged_in %}
<a href="{{ url_for(login) }}">log in</a>
{% else %}
<a href="{{ url_for(logout) }}">log out</a>
{% endif %}
</div>
{% for message in get_flashed_messages() %}
<div class=flash>{{ message }}</div>
{% endfor %}
{% block body %}{% % endblock %}
</div>
35
45
5.8.2 show_entries.html
This template extends the layout.html template from above to display the mes-
sages. Note that the for loop iterates over the messages we passed in with the
render_template()function.Wealsotelltheformtosubmittoyouradd_entryfunction
anduse POSTasHTTPmethod:
{% extends "layout.html" %}
{% block body %}
{% if session.logged_in %}
<form action="{{ url_for(add_entry) }}" method=post class=add-entry>
<dl>
<dt>Title:
<dd><input type=text size=30 name=title>
<dt>Text:
<dd><textarea name=text rows=5 cols=40></textarea>
<dd><input type=submit value=Share>
</dl>
</form>
{% endif %}
<ul class=entries>
{% for entry in entries %}
<li><h2>{{ entry.title }}</h2>{{ entry.text|safe }}
{% else %}
<li><em>Unbelievable. No entries here so far</em>
{% endfor %}
</ul>
{% endblock %}
5.8.3 login.html
Finally the login template which basically just displays a form to allow the user to
login:
{% extends "layout.html" %}
{% block body %}
<h2>Login</h2>
{% if error %}<p class=error><strong>Error:</strong> {{ { error }}{% endif %}
<form action="{{ url_for(login) }}" method=post>
<dl>
<dt>Username:
<dd><input type=text name=username>
<dt>Password:
<dd><input type=password name=password>
<dd><input type=submit value=Login>
</dl>
</form>
{% endblock %}
Continue withStep7: AddingStyle.
36
VB Imaging - VB ISBN Barcode Tutorial PointF(100F, 100F)) docx.Save("C:\\Sample_Barcode.pdf"). barcode settings listed in the above property table. BarcodeType.ISBN 'set barcode data barcode.Data
pdf data extraction open source; how to flatten a pdf form in reader VB Imaging - VB Code 2 of 5 Generator 5 barcode size with parameters listed in the table below. quality Code 2 of 5 on PDF, TIFF, Microsoft of 5 type barcode encoding numeric data text "112233445566
html form output to pdf; how to make a pdf form fillable in reader
41
5.9 Step 7: Adding Style
Now that everything else works, it’s time to add some style tothe application. Just
create astylesheetcalledstyle.cssin the staticfolderwe createdbefore:
body
{ font-family: sans-serif; background: #eee; }
a, h1, h2
{ color: #377ba8; }
h1, h2
{ font-family: Georgia, serif; ; margin: 0; }
h1
{ border-bottom: 2px solid #eee; }
h2
{ font-size: 1.2em; }
.page
{ margin: 2em auto; width: 35em; ; border: 5px solid #ccc;
padding: 0.8em; background: white; }
.entries
{ list-style: none; margin: 0; padding: 0; }
.entries li
{ margin: 0.8em 1.2em; }
.entries li h2 { { margin-left: -1em; }
.add-entry
{ font-size: 0.9em; border-bottom: 1px solid #ccc; }
.add-entry dl
{ font-weight: bold; }
.metanav
{ text-align: right; ; font-size: 0.8em; ; padding: 0.3em;
margin-bottom: 1em; background: #fafafa; }
.flash
{ background: #cee5F5; padding: 0.5em;
border: 1px solid d #aacbe2; }
.error
{ background: #f0d6d6; padding: 0.5em; }
Continue withBonus: TestingtheApplication.
5.10 Bonus: Testing the Application
Now that you have finished the application and everything works as expected, it’s
probablynotabadideatoaddautomatedteststosimplifymodificationsinthefuture.
The applicationaboveisusedasabasicexample of howtoperformunittestingin the
Testing Flask Applications section of the documentation. Go there to see how easy itis
totest Flaskapplications.
37
28
CHAPTER
SIX
TEMPLATES
FlaskleveragesJinja2astemplateengine.Youareobviouslyfreetouseadifferenttem-
plate engine,but you still have toinstall Jinja2 torunFlask itself. Thisrequirementis
necessarytoenable richextensions. Anextensioncan dependonJinja2beingpresent.
This section only gives a very quick introduction into how Jinja2 is integrated into
Flask. If you wantinformationonthetemplate engine’ssyntaxitself,headovertothe
officialJinja2TemplateDocumentation for more information.
6.1 Jinja Setup
Unlesscustomized,Jinja2isconfiguredbyFlaskasfollows:
• autoescaping isenabled for all templates ending in .html, .htm, .xml aswell as
.xhtml
• atemplate hasthe abilitytooptin/outautoescapingwith the {% autoescape %}
tag.
• Flaskinsertsacouple of global functionsandhelpersintothe Jinja2context, ad-
ditionallytothevaluesthat are presentbydefault.
6.2 Standard Context
The followingglobalvariablesare available withinJinja2templatesbydefault:
config
The currentconfigurationobject(flask.config)
Newinversion0.6.
Changed in version 0.10: This is now always available, even in importedtem-
plates.
request
The current request object (flask.request). This variable is unavailable if the
template wasrenderedwithout an activerequestcontext.
39
33
session
The current session object (flask.session). This variable is unavailable if the
template wasrenderedwithout an activerequestcontext.
g
Therequest-boundobjectforglobal variables(flask.g). Thisvariableisunavail-
able ifthe template wasrenderedwithout anactiverequestcontext.
url_for()
The flask.url_for()function.
get_flashed_messages()
The flask.get_flashed_messages()function.
TheJinjaContextBehavior
These variables are added to the context of variables, they are not global variables.
The difference is that by default these will not show up in the context of imported
templates. This is partially caused by performance considerations, partially to keep
thingsexplicit.
What doesthismeanfor you? Ifyou have amacroyou wantto import,thatneedsto
accesstherequestobjectyouhavetwopossibilities:
1. you explicitlypass the requestto the macroasparameter,or the attribute of the
requestobjectyou are interestedin.
2. youimport the macro“withcontext”.
Importingwithcontext lookslike this:
{% from _helpers.html import my_macro with context %}
6.3 Standard Filters
These filtersare available inJinja2additionallytothe filtersprovidedbyJinja2itself:
tojson()
This function converts the given object into JSON representation. This is for
example veryhelpfulifyoutrytogenerate JavaScriptonthefly.
Note that inside scripttagsnoescapingmusttake place,somakesuretodisable
escapingwith|safebeforeFlask0.10ifyouintendtouse it insidescripttags:
<script type=text/javascript>
doSomethingWith({{ user.username|tojson|safe }});
</script>
40
Documents you may be interested
Documents you may be interested