Flask Web Development 1st Edition Miguel
Grinberg download
https://ebookbell.com/product/flask-web-development-1st-edition-
miguel-grinberg-10313190
Explore and download more ebooks at ebookbell.com
Here are some recommended products that we believe you will be
interested in. You can click the link to download.
Flask Web Development Developing Web Applications With Python First
Edition Grinberg
https://ebookbell.com/product/flask-web-development-developing-web-
applications-with-python-first-edition-grinberg-22034586
Flask Web Development Developing Web Applications With Python 2nd
Edition Miguel Grinberg
https://ebookbell.com/product/flask-web-development-developing-web-
applications-with-python-2nd-edition-miguel-grinberg-7316108
Flask Web Development 2nd Edition Miguel Grinberg
https://ebookbell.com/product/flask-web-development-2nd-edition-
miguel-grinberg-10816962
Flask Web Development Developing Web Applications With Python Miguel
Grinberg
https://ebookbell.com/product/flask-web-development-developing-web-
applications-with-python-miguel-grinberg-48508682
Flask Web Development Miguel Grinberg
https://ebookbell.com/product/flask-web-development-miguel-
grinberg-170883436
Mastering Flask Web Development Second Edition Second Edition Daniel
Gaspar
https://ebookbell.com/product/mastering-flask-web-development-second-
edition-second-edition-daniel-gaspar-7339216
Mastering Flask Web Development Daniel Gaspar Jack Stouffer
https://ebookbell.com/product/mastering-flask-web-development-daniel-
gaspar-jack-stouffer-49423062
Mastering Flask Web And Api Development 1st Edition Sherwin John C
Tragura
https://ebookbell.com/product/mastering-flask-web-and-api-
development-1st-edition-sherwin-john-c-tragura-58947898
Mastering Flask Web And Api Development Sherwin John C Tragura
https://ebookbell.com/product/mastering-flask-web-and-api-development-
sherwin-john-c-tragura-74164542
Miguel Grinberg
Flask Web Development
Flask Web Development
by Miguel Grinberg
Copyright © 2014 Miguel Grinberg. All rights reserved.
Printed in the United States of America.
Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472.
O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are
alsoavailableformosttitles(http://my.safaribooksonline.com).Formoreinformation,contactourcorporate/
institutional sales department: 800-998-9938 or corporate@oreilly.com.
Editors: Meghan Blanchette and Rachel Roumeliotis
Production Editor: Nicole Shelby
Copyeditor: Nancy Kotary
Proofreader: Charles Roumeliotis
Cover Designer: Randy Comer
Interior Designer: David Futato
Illustrator: Rebecca Demarest
May 2014: First Edition
Revision History for the First Edition:
2014-04-25: First release
See http://oreilly.com/catalog/errata.csp?isbn=9781449372620 for release details.
Nutshell Handbook, the Nutshell Handbook logo, and the O’Reilly logo are registered trademarks of O’Reilly
Media,Inc.FlaskWebDevelopment,thepictureofaPyreneanMastiff,andrelatedtradedressaretrademarks
of O’Reilly Media, Inc.
Many of the designations used by manufacturers and sellers to distinguish their products are claimed as
trademarks.Wherethosedesignationsappearinthisbook,andO’ReillyMedia,Inc.wasawareofatrademark
claim, the designations have been printed in caps or initial caps.
While every precaution has been taken in the preparation of this book, the publisher and authors assume
no responsibility for errors or omissions, or for damages resulting from the use of the information contained
herein.
ISBN: 978-1-449-37262-0
[LSI]
For Alicia.
Table of Contents
Preface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi
Part I. Introduction to Flask
1. Installation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Using Virtual Environments 4
Installing Python Packages with pip 6
2. Basic Application Structure. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Initialization 7
Routes and View Functions 8
Server Startup 9
A Complete Application 9
The Request-Response Cycle 12
Application and Request Contexts 12
Request Dispatching 14
Request Hooks 14
Responses 15
Flask Extensions 16
Command-Line Options with Flask-Script 17
3. Templates. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
The Jinja2 Template Engine 22
Rendering Templates 22
Variables 23
Control Structures 24
Twitter Bootstrap Integration with Flask-Bootstrap 26
Custom Error Pages 29
Links 31
v
Static Files 32
Localization of Dates and Times with Flask-Moment 33
4. Web Forms. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Cross-Site Request Forgery (CSRF) Protection 37
Form Classes 38
HTML Rendering of Forms 40
Form Handling in View Functions 41
Redirects and User Sessions 44
Message Flashing 46
5. Databases. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
SQL Databases 49
NoSQL Databases 50
SQL or NoSQL? 51
Python Database Frameworks 51
Database Management with Flask-SQLAlchemy 52
Model Definition 54
Relationships 56
Database Operations 57
Creating the Tables 58
Inserting Rows 58
Modifying Rows 60
Deleting Rows 60
Querying Rows 60
Database Use in View Functions 62
Integration with the Python Shell 63
Database Migrations with Flask-Migrate 64
Creating a Migration Repository 64
Creating a Migration Script 65
Upgrading the Database 66
6. Email. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Email Support with Flask-Mail 69
Sending Email from the Python Shell 70
Integrating Emails with the Application 71
Sending Asynchronous Email 72
7. Large Application Structure. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Project Structure 75
Configuration Options 76
Application Package 78
vi | Table of Contents
Using an Application Factory 78
Implementing Application Functionality in a Blueprint 79
Launch Script 81
Requirements File 82
Unit Tests 83
Database Setup 85
Part II. Example: A Social Blogging Application
8. User Authentication. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
Authentication Extensions for Flask 89
Password Security 90
Hashing Passwords with Werkzeug 90
Creating an Authentication Blueprint 92
User Authentication with Flask-Login 94
Preparing the User Model for Logins 94
Protecting Routes 95
Adding a Login Form 96
Signing Users In 97
Signing Users Out 99
Testing Logins 99
New User Registration 100
Adding a User Registration Form 100
Registering New Users 102
Account Confirmation 103
Generating Confirmation Tokens with itsdangerous 103
Sending Confirmation Emails 105
Account Management 109
9. User Roles. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
Database Representation of Roles 111
Role Assignment 113
Role Verification 114
10. User Profiles. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
Profile Information 119
User Profile Page 120
Profile Editor 122
User-Level Profile Editor 122
Administrator-Level Profile Editor 124
Table of Contents | vii
User Avatars 127
11. Blog Posts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Blog Post Submission and Display 131
Blog Posts on Profile Pages 134
Paginating Long Blog Post Lists 135
Creating Fake Blog Post Data 135
Rendering Data on Pages 137
Adding a Pagination Widget 138
Rich-Text Posts with Markdown and Flask-PageDown 141
Using Flask-PageDown 141
Handling Rich Text on the Server 143
Permanent Links to Blog Posts 145
Blog Post Editor 146
12. Followers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
Database Relationships Revisited 149
Many-to-Many Relationships 150
Self-Referential Relationships 151
Advanced Many-to-Many Relationships 152
Followers on the Profile Page 155
Query Followed Posts Using a Database Join 158
Show Followed Posts on the Home Page 160
13. User Comments. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
Database Representation of Comments 165
Comment Submission and Display 167
Comment Moderation 169
14. Application Programming Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
Introduction to REST 175
Resources Are Everything 176
Request Methods 177
Request and Response Bodies 177
Versioning 178
RESTful Web Services with Flask 179
Creating an API Blueprint 179
Error Handling 180
User Authentication with Flask-HTTPAuth 181
Token-Based Authentication 184
Serializing Resources to and from JSON 186
Implementing Resource Endpoints 188
viii | Table of Contents
Pagination of Large Resource Collections 191
Testing Web Services with HTTPie 192
Part III. The Last Mile
15. Testing. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
Obtaining Code Coverage Reports 197
The Flask Test Client 200
Testing Web Applications 200
Testing Web Services 204
End-to-End Testing with Selenium 205
Is It Worth It? 209
16. Performance. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
Logging Slow Database Performance 211
Source Code Profiling 213
17. Deployment. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
Deployment Workflow 215
Logging of Errors During Production 216
Cloud Deployment 217
The Heroku Platform 218
Preparing the Application 218
Testing with Foreman 222
Enabling Secure HTTP with Flask-SSLify 223
Deploying with git push 225
Reviewing Logs 226
Deploying an Upgrade 227
Traditional Hosting 227
Server Setup 227
Importing Environment Variables 228
Setting Up Logging 228
18. Additional Resources. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
Using an Integrated Development Environment (IDE) 231
Finding Flask Extensions 232
Getting Involved with Flask 232
Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
Table of Contents | ix
Preface
Flask stands out from other frameworks because it lets developers take the driver’s seat
and have full creative control of their applications. Maybe you have heard the phrase
“fighting the framework” before. This happens with most frameworks when you decide
to solve a problem with a solution that isn’t the official one. It could be that you want to
use a different database engine, or maybe a different method of authenticating users.
Deviating from the path set by the framework’s developers will give you lots of
headaches.
Flask is not like that. Do you like relational databases? Great. Flask supports them all.
Maybe you prefer a NoSQL database? No problem at all. Flask works with them too.
Want to use your own homegrown database engine? Don’t need a database at all? Still
fine. With Flask you can choose the components of your application or even write your
own if that is what you want. No questions asked!
ThekeytothisfreedomisthatFlaskwasdesignedfromthestarttobeextended.Itcomes
with a robust core that includes the basic functionality that all web applications need
and expects the rest to be provided by some of the many third-party extensions in the
ecosystem and, of course, by you.
In this book I present my workflow for developing web applications with Flask. I don’t
claim to have the only true way to build applications with this framework. You should
take my choices as recommendations and not as gospel.
Most software development books provide small and focused code examples that
demonstratethedifferentfeaturesofthetargettechnologyinisolation,leavingthe“glue”
code that is necessary to transform these different features into a fully working appli‐
cations to be figured out by the reader. I take a completely different approach. All the
examples I present are part of a single application that starts out very simple and is
expanded in each successive chapter. This application begins life with just a few lines of
code and ends as a nicely featured blogging and social networking application.
xi
Who This Book Is For
You should have some level of Python coding experience to make the most of this book.
Although the book assumes no previous Flask knowledge, Python concepts such as
packages, modules, functions, decorators, and object-oriented programming are as‐
sumed to be well understood. Some familiarity with exceptions and diagnosing issues
from stack traces will be very useful.
While working through the examples in this book, you will spend a great deal of time
in the command line. You should feel comfortable using the command line of your
operating system.
Modern web applications cannot avoid the use of HTML, CSS, and JavaScript. The
example application that is developed throughout the book obviously makes use of
these, but the book itself does not go into a lot of detail regarding these technologies
andhowtheyareused.Somedegreeoffamiliaritywiththeselanguagesisrecommended
if you intend to develop complete applications without the help of a developer versed
in client-side techniques.
I released the companion application to this book as open source on GitHub. Although
GitHubmakesitpossibletodownloadapplicationsasregularZIPorTARfiles,Istrongly
recommendthatyouinstallaGitclientandfamiliarizeyourselfwithsourcecodeversion
control, at least with the basic commands to clone and check out the different versions
of the application directly from the repository. The short list of commands that you’ll
need is shown in “How to Work with the Example Code ” on page xiii. You will want to
use version control for your own projects as well, so use this book as an excuse to learn
Git!
Finally, this book is not a complete and exhaustive reference on the Flask framework.
Most features are covered, but you should complement this book with the official Flask
documentation.
How This Book Is Organized
This book is divided into three parts:
Part I, Introduction to Flask, explores the basics of web application development with
the Flask framework and some of its extensions:
• Chapter 1 describes the installation and setup of the Flask framework.
• Chapter 2 dives straight into Flask with a basic application.
• Chapter 3 introduces the use of templates in Flask applications.
• Chapter 4 introduces web forms.
• Chapter 5 introduces databases.
xii | Preface
• Chapter 6 introduces email support.
• Chapter 7 presents an application structure that is appropriate for medium and
large applications.
Part II, Example: A Social Blogging Application, builds Flasky, the open source blogging
and social networking application that I developed for this book:
• Chapter 8 implements a user authentication system.
• Chapter 9 implements user roles and permissions.
• Chapter 10 implements user profile pages.
• Chapter 11 creates the blogging interface.
• Chapter 12 implements followers.
• Chapter 13 implements user comments for blog posts.
• Chapter 14 implements an Application Programming Interface (API).
PartIII,TheLastMile,describessomeimportanttasksnotdirectlyrelatedtoapplication
coding that need to be considered before publishing an application:
• Chapter 15 describes different unit testing strategies in detail.
• Chapter 16 gives an overview of performance analysis techniques.
• Chapter 17 describes deployment options for Flask applications, both traditional
and cloud based.
• Chapter 18 lists additional resources.
How to Work with the Example Code
The code examples presented in this book are available from GitHub at https://
github.com/miguelgrinberg/flasky.
The commit history in this repository was carefully created to match the order in which
concepts are presented in the book. The recommended way to work with the code is to
check out the commits starting from the oldest, then move forward through the commit
list as you make progress with the book. As an alternative, GitHub will also let you
download each commit as a ZIP or TAR file.
If you decide to use Git to work with the source code, then you need to install the Git
client, which you can download from http://git-scm.com. The following command
downloads the example code using Git:
$ git clone https://github.com/miguelgrinberg/flasky.git
Preface | xiii
The git clone command installs the source code from GitHub into a flasky folder that
is created in the current directory. This folder does not contain just source code; a copy
of the Git repository with the entire history of changes made to the application is also
included.
In the first chapter you will be asked to check out the initial release of the application,
and then, at the proper places you will be instructed to move forward in the history.
The Git command that lets you move through the change history is git checkout. Here
is an example:
$ git checkout 1a
The 1a referenced in the command is a tag, a named point in the history of the project.
This repository is tagged according to the chapters of the book, so the 1a tag used in
the example sets the application files to the initial version used in Chapter 1. Most
chapters have more than one tag associated with them, so, for example, tags 5a, 5b, and
so on are incremental versions presented in Chapter 5.
In addition to checking out the source files for a version of the application, you may
need to perform some setup. For example, in some cases you will need to install addi‐
tional Python packages or apply updates to the database. You will be told when these
are necessary.
You will normally not modify the source files of the application, but if you do, then Git
will not let you check out a different revision, as that would cause your local changes to
be lost. Before you can check out a different revision, you will need to revert the files to
their original state. The easiest way to do this is with the git reset command:
$ git reset --hard
This command will destroy your local changes, so you should save anything you don’t
want to lose before you use this command.
From time to time, you may want to refresh your local repository from the one on
GitHub, where bug fixes and improvements may have been applied. The commands
that achieve this are:
$ git fetch --all
$ git fetch --tags
$ git reset --hard origin/master
The git fetch commands are used to update the commit history and the tags in your
local repository from the remote one on GitHub, but none of this affects the actual
source files, which are updated with the git reset command that follows. Once again,
be aware that any time git reset is used you will lose any local changes you have made.
Another useful operation is to view all the differences between two versions of the
application.Thiscanbeveryusefultounderstandachangeindetail.Fromthecommand
xiv | Preface
line, the git diff command can do this. For example, to see the difference between
revisions 2a and 2b, use:
$ git diff 2a 2b
The differences are shown as a patch, which is not a very intuitive format to review
changes if you are not used to working with patch files. You may find that the graphical
comparisons shown by GitHub are much easier to read. For example, the differences
between revisions 2a and 2b can be viewed on GitHub at https://github.com/miguelgrin
berg/flasky/compare/2a...2b
Using Code Examples
This book is here to help you get your job done. In general, if example code is offered
with this book, you may use it in your programs and documentation. You do not need
to contact us for permission unless you’re reproducing a significant portion of the code.
For example, writing a program that uses several chunks of code from this book does
not require permission. Selling or distributing a CD-ROM of examples from O’Reilly
books does require permission. Answering a question by citing this book and quoting
example code does not require permission. Incorporating a significant amount of ex‐
ample code from this book into your product’s documentation does require permission.
We appreciate, but do not require, attribution. An attribution usually includes the title,
author, publisher, and ISBN. For example: “Flask Web Development by Miguel Grinberg
(O’Reilly). Copyright 2014 Miguel Grinberg, 978-1-449-3726-2.”
If you feel your use of code examples falls outside fair use or the permission given above,
feel free to contact us at permissions@oreilly.com.
Conventions Used in This Book
The following typographical conventions are used in this book:
Italic
Indicates new terms, URLs, email addresses, filenames, and file extensions.
Constant width
Used for program listings, as well as within paragraphs to refer to program elements
such as variable or function names, databases, data types, environment variables,
statements, and keywords.
Constant width bold
Shows commands or other text that should be typed literally by the user.
Preface | xv
Constant width italic
Shows text that should be replaced with user-supplied values or by values deter‐
mined by context.
This element signifies a tip or suggestion.
This element signifies a general note.
This element indicates a warning or caution.
Safari® Books Online
Safari Books Online is an on-demand digital library that
delivers expert content in both book and video form from
the world’s leading authors in technology and business.
Technology professionals, software developers, web designers, and business and crea‐
tive professionals use Safari Books Online as their primary resource for research, prob‐
lem solving, learning, and certification training.
Safari Books Online offers a range of product mixes and pricing programs for organi‐
zations, government agencies, and individuals. Subscribers have access to thousands of
books, training videos, and prepublication manuscripts in one fully searchable database
from publishers like O’Reilly Media, Prentice Hall Professional, Addison-Wesley Pro‐
fessional, Microsoft Press, Sams, Que, Peachpit Press, Focal Press, Cisco Press, John
Wiley & Sons, Syngress, Morgan Kaufmann, IBM Redbooks, Packt, Adobe Press, FT
Press, Apress, Manning, New Riders, McGraw-Hill, Jones & Bartlett, Course Technol‐
ogy, and dozens more. For more information about Safari Books Online, please visit us
online.
xvi | Preface
How to Contact Us
Please address comments and questions concerning this book to the publisher:
O’Reilly Media, Inc.
1005 Gravenstein Highway North
Sebastopol, CA 95472
800-998-9938 (in the United States or Canada)
707-829-0515 (international or local)
707-829-0104 (fax)
We have a web page for this book, where we list errata, examples, and any additional
information. You can access this page at http://www.bit.ly/flask-web-dev.
To comment or ask technical questions about this book, send email to bookques
tions@oreilly.com.
For more information about our books, courses, conferences, and news, see our website
at http://www.oreilly.com.
Find us on Facebook: http://facebook.com/oreilly
Follow us on Twitter: http://twitter.com/oreillymedia
Watch us on YouTube: http://www.youtube.com/oreillymedia
Acknowledgments
I could not have written this book alone. I have received a lot of help from family, co-
workers, old friends, and new friends I’ve made along the way.
I’d like to thank Brendan Kohler for his detailed technical review and for his help in
giving shape to the chapter on Application Programming Interfaces. I’m also in debt to
David Baumgold, Todd Brunhoff, Cecil Rock, and Matthew Hugues, who reviewed the
manuscript at different stages of completion and gave me very useful advice regarding
what to cover and how to organize the material.
Writing the code examples for this book was a considerable effort. I appreciate the help
of Daniel Hofmann, who did a thorough code review of the application and pointed out
several improvements. I’m also thankful to my teenage son, Dylan Grinberg, who sus‐
pended his Minecraft addiction for a few weekends and helped me test the code under
several platforms.
O’Reilly has a wonderful program called Early Release that allows impatient readers to
have access to books while they are being written. Some of my Early Release readers
went the extra mile and engaged in useful conversations regarding their experience
working through the book, leading to significant improvements. I’d like to acknowledge
Preface | xvii
Sundeep Gupta, Dan Caron, Brian Wisti and Cody Scott in particular for the contri‐
butions they’ve made to this book.
The staff at O’Reilly Media has always been there for me. Above all I’d like to recognize
my wonderful editor, Meghan Blanchette, for her support, advice, and assistance from
the very first day we met. Meg has made the experience of writing my first book a
memorable one.
To conclude, I would like to give a big thank you to the awesome Flask community.
xviii | Preface
PART I
Introduction to Flask
CHAPTER 1
Installation
Flask is a small framework by most standards, small enough to be called a “micro-
framework.” It is small enough that once you become familiar with it, you will likely be
able to read and understand all of its source code.
But being small does not mean that it does less than other frameworks. Flask was de‐
signed as an extensible framework from the ground up; it provides a solid core with the
basic services, while extensions provide the rest. Because you can pick and choose the
extension packages that you want, you end up with a lean stack that has no bloat and
does exactly what you need.
Flask has two main dependencies. The routing, debugging, and Web Server Gateway
Interface (WSGI) subsystems come from Werkzeug, while template support is provided
by Jinja2. Werkzeug and Jinja2 are authored by the core developer of Flask.
There is no native support in Flask for accessing databases, validating web forms, au‐
thenticating users, or other high-level tasks. These and many other key services most
web applications need are available through extensions that integrate with the core
packages. As a developer, you have the power to cherry-pick the extensions that work
best for your project or even write your own if you feel inclined to. This is in contrast
with a larger framework, where most choices have been made for you and are hard or
sometimes impossible to change.
In this chapter, you will learn how to install Flask. The only requirement you need is a
computer with Python installed.
The code examples in this book have been verified to work with
Python 2.7 and Python 3.3, so using one of these two versions is
strongly recommended.
3
Using Virtual Environments
The most convenient way to install Flask is to use a virtual environment. A virtual
environment is a private copy of the Python interpreter onto which you can install
packages privately, without affecting the global Python interpreter installed in your
system.
Virtual environments are very useful because they prevent package clutter and version
conflicts in the system’s Python interpreter. Creating a virtual environment for each
application ensures that applications have access to only the packages that they use,
while the global interpreter remains neat and clean and serves only as a source from
which more virtual environments can be created. As an added benefit, virtual environ‐
ments don’t require administrator rights.
Virtual environments are created with the third-party virtualenv utility. To check
whether you have it installed in your system, type the following command:
$ virtualenv --version
If you get an error, you will have to install the utility.
Python 3.3 adds native support of virtual environments through the
venv module and the pyvenv command. pyvenv can be used instead
of virtualenv, but note that virtual environments created with py‐
venv on Python 3.3 do not include pip, which needs to be installed
manually. This limitation has been removed in Python 3.4, where
pyvenv can be used as a complete virtualenv replacement.
Most Linux distributions provide a package for virtualenv. For example, Ubuntu users
can install it with this command:
$ sudo apt-get install python-virtualenv
If you are using Mac OS X, then you can install virtualenv using easy_install:
$ sudo easy_install virtualenv
If you are using Microsoft Windows or any operating system that does not provide an
official virtualenv package, then you have a slightly more complicated install procedure.
Using your web browser, navigate to https://bitbucket.org/pypa/setuptools, the home of
the setuptools installer. In that page, look for a link to download the installer script.
This is a script called ez_setup.py. Save this file to a temporary folder on your computer,
then run the following commands in that folder:
$ python ez_setup.py
$ easy_install virtualenv
4 | Chapter 1: Installation
The previous commands must be issued from an account with ad‐
ministrator rights. On Microsoft Windows, start the command
prompt window using the “Run as Administrator” option. On Unix-
based systems, the two installation commands must be preceded with
sudo or executed as the root user. Once installed, the virtualenv util‐
ity can be invoked from regular accounts.
Now you need to create the folder that will host the example code, which is available
from a GitHub repository. As discussed in “How to Work with the Example Code ” on
page xiii, the most convenient way to do this is by checking out the code directly from
GitHub using a Git client. The following commands download the example code from
GitHub and initialize the application folder to version “1a,” the initial version of the
application:
$ git clone https://github.com/miguelgrinberg/flasky.git
$ cd flasky
$ git checkout 1a
The next step is to create the Python virtual environment inside the flasky folder using
the virtualenv command. This command has a single required argument: the name of
the virtual environment. A folder with the chosen name will be created in the current
directory and all files associated with the virtual environment will be inside. A com‐
monly used naming convention for virtual environments is to call them venv:
$ virtualenv venv
New python executable in venv/bin/python2.7
Also creating executable in venv/bin/python
Installing setuptools............done.
Installing pip...............done.
Now you have a venv folder inside the flasky folder with a brand-new virtual environ‐
ment that contains a private Python interpreter. To start using the virtual environment,
you have to “activate” it. If you are using a bash command line (Linux and Mac OS X
users), you can activate the virtual environment with this command:
$ source venv/bin/activate
If you are using Microsoft Windows, the activation command is:
$ venvScriptsactivate
When a virtual environment is activated, the location of its Python interpreter is added
to the PATH, but this change is not permanent; it affects only your current command
session. To remind you that you have activated a virtual environment, the activation
command modifies the command prompt to include the name of the environment:
(venv) $
Using Virtual Environments | 5
When you are done working with the virtual environment and want to return to the
global Python interpreter, type deactivate at the command prompt.
Installing Python Packages with pip
Most Python packages are installed with the pip utility, which virtualenv automatically
addstoallvirtualenvironmentsuponcreation.Whenavirtualenvironmentisactivated,
the location of the pip utility is added to the PATH.
If you created the virtual environment with pyvenv under Python 3.3,
then pip must be installed manually. Installation instructions are
available on the pip website. Under Python 3.4, pyvenv installs pip
automatically.
To install Flask into the virtual environment, use the following command:
(venv) $ pip install flask
Withthiscommand,Flaskanditsdependenciesareinstalledinthevirtualenvironment.
You can verify that Flask was installed correctly by starting the Python interpreter and
trying to import it:
(venv) $ python
>>> import flask
>>>
If no errors appear, you can congratulate yourself: you are ready for the next chapter,
where you will write your first web application.
6 | Chapter 1: Installation
CHAPTER 2
Basic Application Structure
In this chapter, you will learn about the different parts of a Flask application. You will
also write and run your first Flask web application.
Initialization
All Flask applications must create an application instance. The web server passes all
requests it receives from clients to this object for handling, using a protocol called Web
Server Gateway Interface (WSGI). The application instance is an object of class Flask,
usually created as follows:
from flask import Flask
app = Flask(__name__)
The only required argument to the Flask class constructor is the name of the main
moduleorpackageoftheapplication.Formostapplications,Python’s__name__ variable
is the correct value.
The name argument that is passed to the Flask application construc‐
tor is a source of confusion among new Flask developers. Flask uses
this argument to determine the root path of the application so that it
later can find resource files relative to the location of the application.
Later you will see more complex examples of application initialization, but for simple
applications this is all that is needed.
7
Routes and View Functions
Clients such as web browsers send requests to the web server, which in turn sends them
to the Flask application instance. The application instance needs to know what code
needstorunforeachURLrequested,soitkeepsamappingofURLstoPythonfunctions.
The association between a URL and the function that handles it is called a route.
The most convenient way to define a route in a Flask application is through the
app.route decorator exposed by the application instance, which registers the decorated
function as a route. The following example shows how a route is declared using this
decorator:
@app.route('/')
def index():
return '<h1>Hello World!</h1>'
Decorators are a standard feature of the Python language; they can
modify the behavior of a function in different ways. A common pat‐
tern is to use decorators to register functions as handlers for an event.
The previous example registers the function index() as the handler for the application’s
root URL. If this application were deployed on a server associated with the www.ex‐
ample.com domain name, then navigating to http://www.example.com on your browser
would trigger index() to run on the server. The return value of this function, called the
response, is what the client receives. If the client is a web browser, the response is the
document that is displayed to the user.
Functionslikeindex() arecalledviewfunctions.Aresponsereturnedbyaviewfunction
can be a simple string with HTML content, but it can also take more complex forms, as
you will see later.
Response strings embedded in Python code lead to code that is dif‐
ficult to maintain, and it is done here only to introduce the concept
of responses. You will learn the proper way to generate responses in
Chapter 3.
If you pay attention to how some URLs for services that you use every day are formed,
you will notice that many have variable sections. For example, the URL for your Face‐
book profile page is http://www.facebook.com/<your-name>, so your username is part
of it. Flask supports these types of URLs using a special syntax in the route decorator.
The following example defines a route that has a dynamic name component:
8 | Chapter 2: Basic Application Structure
@app.route('/user/<name>')
def user(name):
return '<h1>Hello, %s!</h1>' % name
The portion enclosed in angle brackets is the dynamic part, so any URLs that match the
static portions will be mapped to this route. When the view function is invoked, Flask
sends the dynamic component as an argument. In the earlier example view function,
this argument is used to generate a personalized greeting as a response.
The dynamic components in routes are strings by default but can also be defined with
atype.Forexample,route/user/<int:id> wouldmatchonlyURLsthathaveaninteger
in the id dynamic segment. Flask supports types int, float, and path for routes. The
path type also represents a string but does not consider slashes as separators and instead
considers them part of the dynamic component.
Server Startup
The application instance has a run method that launches Flask’s integrated development
web server:
if __name__ == '__main__':
app.run(debug=True)
The __name__ == '__main__' Python idiom is used here to ensure that the develop‐
ment web server is started only when the script is executed directly. When the script is
imported by another script, it is assumed that the parent script will launch a different
server, so the app.run() call is skipped.
Once the server starts up, it goes into a loop that waits for requests and services them.
This loop continues until the application is stopped, for example by hitting Ctrl-C.
There are several option arguments that can be given to app.run() to configure the
mode of operation of the web server. During development, it is convenient to enable
debug mode, which among other things activates the debugger and the reloader. This is
done by passing the argument debug set to True.
The web server provided by Flask is not intended for production use.
You will learn about production web servers in Chapter 17.
A Complete Application
In the previous sections, you learned about the different parts of a Flask web application,
and now it is time to write one. The entire hello.py application script is nothing more
Server Startup | 9
than the three parts described earlier combined in a single file. The application is shown
in Example 2-1.
Example 2-1. hello.py: A complete Flask application
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return '<h1>Hello World!</h1>'
if __name__ == '__main__':
app.run(debug=True)
If you have cloned the application’s Git repository on GitHub, you can
now run git checkout 2a to check out this version of the application.
To run the application, make sure that the virtual environment you created earlier is
activated and has Flask installed. Now open your web browser and type http://
127.0.0.1:5000/ in the address bar. Figure 2-1 shows the web browser after connecting
to the application.
Figure 2-1. hello.py Flask application
Then launch the application with the following command:
10 | Chapter 2: Basic Application Structure
(venv) $ python hello.py
* Running on http://127.0.0.1:5000/
* Restarting with reloader
If you type any other URL, the application will not know how to handle it and will return
an error code 404 to the browser—the familiar error that you get when you navigate to
a web page that does not exist.
The enhanced version of the application shown in Example 2-2 adds a second route that
is dynamic. When you visit this URL, you are presented with a personalized greeting.
Example 2-2. hello.py: Flask application with a dynamic route
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return '<h1>Hello World!</h1>'
@app.route('/user/<name>')
def user(name):
return '<h1>Hello, %s!</h1>' % name
if __name__ == '__main__':
app.run(debug=True)
If you have cloned the application’s Git repository on GitHub, you can
now run git checkout 2b to check out this version of the application.
To test the dynamic route, make sure the server is running and then navigate to http://
localhost:5000/user/Dave. The application will respond with a customized greeting,
generated using the name dynamic argument. Try different names to see how the view
function always generates the response based on the name given. An example is shown
in Figure 2-2.
A Complete Application | 11
Figure 2-2. Dynamic route
The Request-Response Cycle
Now that you have played with a basic Flask application, you might want to know more
about how Flask works its magic. The following sections describe some of the design
aspects of the framework.
Application and Request Contexts
When Flask receives a request from a client, it needs to make a few objects available to
the view function that will handle it. A good example is the request object, which en‐
capsulates the HTTP request sent by the client.
The obvious way in which Flask could give a view function access to the request object
is by sending it as an argument, but that would require every single view function in the
application to have an extra argument. Things get more complicated if you consider
that the request object is not the only object that view functions might need to access
to fulfill a request.
Toavoidclutteringviewfunctionswithlotsofargumentsthatmayormaynotbeneeded,
Flask uses contexts to temporarily make certain objects globally accessible. Thanks to
contexts, view functions like the following one can be written:
from flask import request
@app.route('/')
def index():
12 | Chapter 2: Basic Application Structure
user_agent = request.headers.get('User-Agent')
return '<p>Your browser is %s</p>' % user_agent
Note how in this view function request is used as if it was a global variable. In reality,
request cannot be a global variable if you consider that in a multithreaded server the
threads are working on different requests from different clients at the same time, so
each thread needs to see a different object in request. Contexts enable Flask to make
certain variables globally accessible to a thread without interfering with the other
threads.
A thread is the smallest sequence of instructions that can be man‐
aged independently. It is common for a process to have multiple ac‐
tive threads, sometimes sharing resources such as memory or file
handles. Multithreaded web servers start a pool of threads and se‐
lect a thread from the pool to handle each incoming request.
TherearetwocontextsinFlask:theapplicationcontextandtherequestcontext.Table2-1
shows the variables exposed by each of these contexts.
Table 2-1. Flask context globals
Variable name Context Description
current_app Application context The application instance for the active application.
g Application context An object that the application can use for temporary storage during the handling of
a request. This variable is reset with each request.
request Request context The request object, which encapsulates the contents of a HTTP request sent by the
client.
session Request context The user session, a dictionary that the application can use to store values that are
“remembered” between requests.
Flask activates (or pushes) the application and request contexts before dispatching a
request and then removes them when the request is handled. When the application
context is pushed, the current_app and g variables become available to the thread;
likewise, when the request context is pushed, request and session become available
as well. If any of these variables are accessed without an active application or request
context, an error is generated. The four context variables will be revisited in later chap‐
ters in detail, so don’t worry if you don’t understand why they are useful yet.
The following Python shell session demonstrates how the application context works:
>>> from hello import app
>>> from flask import current_app
>>> current_app.name
Traceback (most recent call last):
...
RuntimeError: working outside of application context
The Request-Response Cycle | 13
>>> app_ctx = app.app_context()
>>> app_ctx.push()
>>> current_app.name
'hello'
>>> app_ctx.pop()
In this example, current_app.name fails when there is no application context active but
becomes valid once a context is pushed. Note how an application context is obtained
by invoking app.app_context() on the application instance.
Request Dispatching
Whentheapplicationreceivesarequestfromaclient,itneedstofindwhatviewfunction
to invoke to service it. For this task, Flask looks up the URL given in the request in the
application’s URL map, which contains a mapping of URLs to the view functions that
handle them. Flask builds this map using the app.route decorators or the equivalent
nondecorator version app.add_url_rule().
To see what the URL map in a Flask application looks like, you can inspect the map
created for hello.py in the Python shell. For this test, make sure that your virtual envi‐
ronment is activated:
(venv) $ python
>>> from hello import app
>>> app.url_map
Map([<Rule '/' (HEAD, OPTIONS, GET) -> index>,
<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
<Rule '/user/<name>' (HEAD, OPTIONS, GET) -> user>])
The / and /user/<name> routes were defined by the app.route decorators in the ap‐
plication. The /static/<filename> route is a special route added by Flask to give access
to static files. You will learn more about static files in Chapter 3.
The HEAD, OPTIONS, GET elements shown in the URL map are the request methods that
are handled by the route. Flask attaches methods to each route so that different request
methods sent to the same URL can be handled by different view functions. The HEAD
and OPTIONS methods are managed automatically by Flask, so in practice it can be said
that in this application the three routes in the URL map are attached to the GET method.
You will learn about specifying different request methods for routes in Chapter 4.
Request Hooks
Sometimes it is useful to execute code before or after each request is processed. For
example, at the start of each request it may be necessary to create a database connection,
or authenticate the user making the request. Instead of duplicating the code that does
this in every view function, Flask gives you the option to register common functions to
be invoked before or after a request is dispatched to a view function.
14 | Chapter 2: Basic Application Structure
Request hooks are implemented as decorators. These are the four hooks supported by
Flask:
• before_first_request: Register a function to run before the first request is
handled.
• before_request: Register a function to run before each request.
• after_request: Register a function to run after each request, if no unhandled ex‐
ceptions occurred.
• teardown_request: Register a function to run after each request, even if unhandled
exceptions occurred.
A common pattern to share data between request hook functions and view functions is
to use the g context global. For example, a before_request handler can load the logged-
inuserfromthedatabaseandstoreiting.user.Later,whentheviewfunctionisinvoked,
it can access the user from there.
Examples of request hooks will be shown in future chapters, so don’t worry if this does
not quite make sense yet.
Responses
When Flask invokes a view function, it expects its return value to be the response to the
request. In most cases the response is a simple string that is sent back to the client as an
HTML page.
But the HTTP protocol requires more than a string as a response to a request. A very
important part of the HTTP response is the status code, which Flask by default sets to
200, the code that indicates that the request was carried out successfully.
When a view function needs to respond with a different status code, it can add the
numericcodeasasecondreturnvalueaftertheresponsetext.Forexample,thefollowing
view function returns a 400 status code, the code for a bad request error:
@app.route('/')
def index():
return '<h1>Bad Request</h1>', 400
Responses returned by view functions can also take a third argument, a dictionary of
headers that are added to the HTTP response. This is rarely needed, but you will see an
example in Chapter 14.
Instead of returning one, two, or three values as a tuple, Flask view functions have the
option of returning a Response object. The make_response() function takes one, two,
or three arguments, the same values that can be returned from a view function, and
returns a Response object. Sometimes it is useful to perform this conversion inside the
The Request-Response Cycle | 15
view function and then use the methods of the response object to further configure the
response. The following example creates a response object and then sets a cookie in it:
from flask import make_response
@app.route('/')
def index():
response = make_response('<h1>This document carries a cookie!</h1>')
response.set_cookie('answer', '42')
return response
There is a special type of response called a redirect. This response does not include a
page document; it just gives the browser a new URL from which to load a new page.
Redirects are commonly used with web forms, as you will learn in Chapter 4.
A redirect is typically indicated with a 302 response status code and the URL to redirect
to given in a Location header. A redirect response can be generated using a three-value
return, or also with a Response object, but given its frequent use, Flask provides a
redirect() helper function that creates this response:
from flask import redirect
@app.route('/')
def index():
return redirect('http://www.example.com')
Another special response is issued with the abort function, which is used for error
handling. The following example returns status code 404 if the id dynamic argument
given in the URL does not represent a valid user:
from flask import abort
@app.route('/user/<id>')
def get_user(id):
user = load_user(id)
if not user:
abort(404)
return '<h1>Hello, %s</h1>' % user.name
Notethatabortdoesnotreturncontrolbacktothefunctionthatcallsitbutgivescontrol
back to the web server by raising an exception.
Flask Extensions
Flask is designed to be extended. It intentionally stays out of areas of important func‐
tionality such as database and user authentication, giving you the freedom to select the
packages that fit your application the best, or to write your own if you so desire.
16 | Chapter 2: Basic Application Structure
There is a large variety of extensions for many different purposes that were created by
the community, and if that is not enough, any standard Python package or library can
be used as well. To give you an idea of how an extension is incorporated into an appli‐
cation, the following section adds an extension to hello.py that enhances the application
with command-line arguments.
Command-Line Options with Flask-Script
Flask’s development web server supports a number of startup configuration options,
but the only way to specify them is by passing them as arguments to the app.run() call
in the script. This is not very convenient; the ideal way to pass configuration options is
through command-line arguments.
Flask-Script is an extension for Flask that adds a command-line parser to your Flask
application. It comes packaged with a set of general-purpose options and also supports
custom commands.
The extension is installed with pip:
(venv) $ pip install flask-script
Example 2-3 shows the changes needed to add command-line parsing to the hello.py
application.
Example 2-3. hello.py: Using Flask-Script
from flask.ext.script import Manager
manager = Manager(app)
# ...
if __name__ == '__main__':
manager.run()
Extensions developed specifically for Flask are exposed under the flask.ext name‐
space. Flask-Script exports a class named Manager, which is imported from
flask.ext.script.
The method of initialization of this extension is common to many extensions: an in‐
stance of the main class is initialized by passing the application instance as an argument
to the constructor. The created object is then used as appropriate for each extension. In
this case, the server startup is routed through manager.run(), where the command line
is parsed.
Flask Extensions | 17
If you have cloned the application’s Git repository on GitHub, you can
run git checkout 2c to check out this version of the application.
With these changes, the application acquires a basic set of command-line options. Run‐
ning hello.py now shows a usage message:
$ python hello.py
usage: hello.py [-h] {shell,runserver} ...
positional arguments:
{shell,runserver}
shell Runs a Python shell inside Flask application context.
runserver Runs the Flask development server i.e. app.run()
optional arguments:
-h, --help show this help message and exit
The shell command is used to start a Python shell session in the context of the appli‐
cation. You can use this session to run maintenance tasks or tests, or to debug issues.
The runserver command, as its name implies, starts the web server. Running python
hello.py runserver startsthewebserverindebugmode,buttheremanymoreoptions
available:
(venv) $ python hello.py runserver --help
usage: hello.py runserver [-h] [-t HOST] [-p PORT] [--threaded]
[--processes PROCESSES] [--passthrough-errors] [-d]
[-r]
Runs the Flask development server i.e. app.run()
optional arguments:
-h, --help show this help message and exit
-t HOST, --host HOST
-p PORT, --port PORT
--threaded
--processes PROCESSES
--passthrough-errors
-d, --no-debug
-r, --no-reload
The --host argument is a useful option because it tells the web server what network
interface to listen to for connections from clients. By default, Flask’s development web
server listens for connections on localhost, so only connections originating from
within the computer running the server are accepted. The following command makes
the web server listen for connections on the public network interface, enabling other
computers in the network to connect as well:
18 | Chapter 2: Basic Application Structure
(venv) $ python hello.py runserver --host 0.0.0.0
* Running on http://0.0.0.0:5000/
* Restarting with reloader
The web server should now be accessible from any computer in the network at http://
a.b.c.d:5000, where “a.b.c.d” is the external IP address of the computer running the
server.
This chapter introduced the concept of responses to requests, but there is a lot more to
say about responses. Flask provides very good support for generating responses using
templates, and this is such an important topic that the next chapter is dedicated to it.
Flask Extensions | 19
CHAPTER 3
Templates
The key to writing applications that are easy to maintain is to write clean and well-
structured code. The examples that you have seen so far are too simple to demonstrate
this, but Flask view functions have two completely independent purposes disguised as
one, which creates a problem.
The obvious task of a view function is to generate a response to a request, as you have
seen in the examples shown in Chapter 2. For the simplest requests this is enough, but
ingeneralarequesttriggersachangeinthestateoftheapplication,andtheviewfunction
is also where this change is generated.
For example, consider a user who is registering a new account on a website. The user
types an email address and a password in a web form and clicks the Submit button. On
the server, a request that includes the data from the user arrives and Flask dispatches it
to the view function that handles registration requests. This view function needs to talk
to the database to get the new user added and then generate a response to send back to
the browser. These two types of tasks are formally called business logic and presentation
logic, respectively.
Mixing business and presentation logic leads to code that is hard to understand and
maintain. Imagine having to build the HTML code for a large table by concatenating
data obtained from the database with the necessary HTML string literals. Moving the
presentation logic into templates helps improve the maintainability of the application.
A template is a file that contains the text of a response, with placeholder variables for
the dynamic parts that will be known only in the context of a request. The process that
replaces the variables with actual values and returns a final response string is called
rendering. For the task of rendering templates, Flask uses a powerful template engine
called Jinja2.
21
The Jinja2 Template Engine
In its simplest form, a Jinja2 template is a file that contains the text of a response.
Example 3-1 shows a Jinja2 template that matches the response of the index() view
function of Example 2-1.
Example 3-1. templates/index.html: Jinja2 template
<h1>Hello World!</h1>
The response returned by view function user() of Example 2-2 has a dynamic com‐
ponent, which is represented by a variable. Example 3-2 shows the template that im‐
plements this response.
Example 3-2. templates/user.html: Jinja2 template
<h1>Hello, {{ name }}!</h1>
Rendering Templates
By default Flask looks for templates in a templates subfolder located inside the applica‐
tion folder. For the next version of hello.py, you need to store the templates defined
earlier in a new templates folder as index.html and user.html.
The view functions in the application need to be modified to render these templates.
Example 3-3 shows these changes.
Example 3-3. hello.py: Rendering a template
from flask import Flask, render_template
# ...
@app.route('/index')
def index():
return render_template('index.html')
@app.route('/user/<name>')
def user(name):
return render_template('user.html', name=name)
The function render_template provided by Flask integrates the Jinja2 template engine
with the application. This function takes the filename of the template as its first argu‐
ment. Any additional arguments are key/value pairs that represent actual values for
variables referenced in the template. In this example, the second template is receiving
a name variable.
Keyword arguments like name=name in the previous example are fairly common but may
seem confusing and hard to understand if you are not used to them. The “name” on the
22 | Chapter 3: Templates
left side represents the argument name, which is used in the placeholder written in the
template. The “name” on the right side is a variable in the current scope that provides
the value for the argument of the same name.
If you have cloned the application’s Git repository on GitHub, you can
run git checkout 3a to check out this version of the application.
Variables
The {{ name }} construct used in the template shown in Example 3-2 references a
variable, a special placeholder that tells the template engine that the value that goes in
that place should be obtained from data provided at the time the template is rendered.
Jinja2 recognizes variables of any type, even complex types such as lists, dictionaries
and objects. The following are some more examples of variables used in templates:
<p>A value from a dictionary: {{ mydict['key'] }}.</p>
<p>A value from a list: {{ mylist[3] }}.</p>
<p>A value from a list, with a variable index: {{ mylist[myintvar] }}.</p>
<p>A value from an object's method: {{ myobj.somemethod() }}.</p>
Variables can be modified with filters, which are added after the variable name with a
pipe character as separator. For example, the following template shows the name variable
capitalized:
Hello, {{ name|capitalize }}
Table 3-1 lists some of the commonly used filters that come with Jinja2.
Table 3-1. Jinja2 variable filters
Filter name Description
safe Renders the value without applying escaping
capitalize Converts the first character of the value to uppercase and the rest to lowercase
lower Converts the value to lowercase characters
upper Converts the value to uppercase characters
title Capitalizes each word in the value
trim Removes leading and trailing whitespace from the value
striptags Removes any HTML tags from the value before rendering
The safe filter is interesting to highlight. By default Jinja2 escapes all variables for se‐
curity purposes. For example, if a variable is set to the value '<h1>Hello</h1>', Jinja2
The Jinja2 Template Engine | 23
will render the string as '&lt;h1&gt;Hello&lt;/h1&gt;', which will cause the h1 ele‐
ment to be displayed and not interpreted by the browser. Many times it is necessary to
display HTML code stored in variables, and for those cases the safe filter is used.
Never use the safe filter on values that aren’t trusted, such as text
entered by users on web forms.
The complete list of filters can be obtained from the official Jinja2 documentation.
Control Structures
Jinja2 offers several control structures that can be used to alter the flow of the template.
This section introduces some of the most useful ones with simple examples.
The following example shows how conditional statements can be entered in a template:
{% if user %}
Hello, {{ user }}!
{% else %}
Hello, Stranger!
{% endif %}
Another common need in templates is to render a list of elements. This example shows
how this can be done with a for loop:
<ul>
{% for comment in comments %}
<li>{{ comment }}</li>
{% endfor %}
</ul>
Jinja2 also supports macros, which are similar to functions in Python code. For example:
{% macro render_comment(comment) %}
<li>{{ comment }}</li>
{% endmacro %}
<ul>
{% for comment in comments %}
{{ render_comment(comment) }}
{% endfor %}
</ul>
To make macros more reusable, they can be stored in standalone files that are then
imported from all the templates that need them:
{% import 'macros.html' as macros %}
<ul>
24 | Chapter 3: Templates
{% for comment in comments %}
{{ macros.render_comment(comment) }}
{% endfor %}
</ul>
Portions of template code that need to be repeated in several places can be stored in a
separate file and included from all the templates to avoid repetition:
{% include 'common.html' %}
Yet another powerful way to reuse is through template inheritance, which is similar to
class inheritance in Python code. First, a base template is created with the name
base.html:
<html>
<head>
{% block head %}
<title>{% block title %}{% endblock %} - My Application</title>
{% endblock %}
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>
Here the block tags define elements that a derived template can change. In this example,
there are blocks called head, title, and body; note that title is contained by head. The
following example is a derived template of the base template:
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}
<style>
</style>
{% endblock %}
{% block body %}
<h1>Hello, World!</h1>
{% endblock %}
The extends directive declares that this template derives from base.html. This directive
is followed by new definitions for the three blocks defined in the base template, which
are inserted in the proper places. Note that the new definition of the head block, which
is not empty in the base template, uses super() to retain the original contents.
Real-world usage of all the control structures presented in this section will be shown
later, so you will have the opportunity to see how they work.
The Jinja2 Template Engine | 25
Twitter Bootstrap Integration with Flask-Bootstrap
Bootstrap is an open source framework from Twitter that provides user interface com‐
ponents to create clean and attractive web pages that are compatible with all modern
web browsers.
Bootstrap is a client-side framework, so the server is not directly involved with it. All
the server needs to do is provide HTML responses that reference Bootstrap’s cascading
style sheets (CSS) and JavaScript files and instantiate the desired components through
HTML, CSS, and JavaScript code. The ideal place to do all this is in templates.
The obvious way to integrate Bootstrap with the application is to make all the necessary
changes to the templates. A simpler approach is to use a Flask extension called Flask-
Bootstrap to simplify the integration effort. Flask-Bootstrap can be installed with pip:
(venv) $ pip install flask-bootstrap
Flask extensions are usually initialized at the same time the application instance is cre‐
ated. Example 3-4 shows the initialization of Flask-Bootstrap.
Example 3-4. hello.py: Flask-Bootstrap initialization
from flask.ext.bootstrap import Bootstrap
# ...
bootstrap = Bootstrap(app)
Like Flask-Script in Chapter 2, Flask-Bootstrap is imported from the flask.ext name‐
space and initialized by passing the application instance in the constructor.
Once Flask-Bootstrap is initialized, a base template that includes all the Bootstrap files
is available to the application. This template takes advantage of Jinja2’s template inher‐
itance; the application extends a base template that has the general structure of the page
including the elements that import Bootstrap. Example 3-5 shows a new version of
user.html as a derived template.
Example 3-5. templates/user.html: Template that uses Flask-Bootstrap
{% extends "bootstrap/base.html" %}
{% block title %}Flasky{% endblock %}
{% block navbar %}
<div class="navbar navbar-inverse" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle"
data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
26 | Chapter 3: Templates
</button>
<a class="navbar-brand" href="/">Flasky</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a href="/">Home</a></li>
</ul>
</div>
</div>
</div>
{% endblock %}
{% block content %}
<div class="container">
<div class="page-header">
<h1>Hello, {{ name }}!</h1>
</div>
</div>
{% endblock %}
The Jinja2 extends directive implements the template inheritance by referencing boot‐
strap/base.htmlfromFlask-Bootstrap.ThebasetemplatefromFlask-Bootstrapprovides
a skeleton web page that includes all the Bootstrap CSS and JavaScript files.
Base templates define blocks that can be overriden by derived templates. The block and
endblock directives define blocks of content that are added to the base template.
The user.html template above defines three blocks called title, navbar, and content.
These are all blocks that the base template exports for derived templates to define. The
title block is straightforward; its contents will appear between <title> tags in the
header of the rendered HTML document. The navbar and content blocks are reserved
for the page navigation bar and main content.
In this template, the navbar block defines a simple navigation bar using Bootstrap com‐
ponents. The content block has a container <div> with a page header inside. The greet‐
ing line that was in the previous version of the template is now inside the page header.
Figure 3-1 shows how the application looks with these changes.
If you have cloned the application’s Git repository on GitHub, you can
run git checkout 3b to check out this version of the application.
The Bootstrap official documentation is a great learning resource full
of copy/paste-ready examples.
Twitter Bootstrap Integration with Flask-Bootstrap | 27
Figure 3-1. Twitter Bootstrap templates
Flask-Bootstrap’s base.html template defines several other blocks that can be used in
derived templates. Table 3-2 shows the complete list of available blocks.
Table 3-2. Flask-Bootstrap’s base template blocks
Block name Description
doc The entire HTML document
html_attribs Attributes inside the <html> tag
html The contents of the <html> tag
head The contents of the <head> tag
title The contents of the <title> tag
metas The list of <meta> tags
styles Cascading stylesheet definitions
body_attribs Attributes inside the <body> tag
body The contents of the <body> tag
navbar User-defined navigation bar
content User-defined page content
scripts JavaScript declarations at the bottom of the document
Many of the blocks in Table 3-2 are used by Flask-Bootstrap itself, so overriding them
directly would cause problems. For example, the styles and scripts blocks are where
the Bootstrap files are declared. If the application needs to add its own content to a block
thatalreadyhassomecontent,thenJinja2’ssuper()functionmustbeused.Forexample,
28 | Chapter 3: Templates
this is how the scripts block would need to be written in the derived template to add
a new JavaScript file to the document:
{% block scripts %}
{{ super() }}
<script type="text/javascript" src="my-script.js"></script>
{% endblock %}
Custom Error Pages
When you enter an invalid route in your browser’s address bar, you get a code 404 error
page. The error page is now too plain and unattractive, and it has no consistency with
the page that uses Bootstrap.
Flask allows an application to define custom error pages that can be based on templates,
likeregularroutes.Thetwomostcommonerrorcodesare404,triggeredwhentheclient
requestsapageorroutethatisnotknown,and500,triggeredwhenthereisanunhandled
exception. Example 3-6 shows how to provide custom handlers for these two errors.
Example 3-6. hello.py: Custom error pages
@app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
@app.errorhandler(500)
def internal_server_error(e):
return render_template('500.html'), 500
Error handlers return a response, like view functions. They also return the numeric
status code that corresponds to the error.
The templates referenced in the error handlers need to be written. These templates
should follow the same layout of the regular pages, so in this case they will have a
navigation bar and a page header that shows the error message.
The straightforward way to write these templates is to copy templates/user.html to
templates/404.html and templates/500.html and then change the page header element
in these two new files to the appropriate error message, but this will generate a lot of
duplication.
Jinja2’s template inheritance can help with this. In the same way Flask-Bootstrap pro‐
vides a base template with the basic layout of the page, the application can define its
own base template with a more complete page layout that includes the navigation bar
and leaves the page content to be defined in derived templates. Example 3-7 shows
templates/base.html, a new template that inherits from bootstrap/base.html and defines
the navigation bar, but is itself a base template to other templates such as templates/
user.html, templates/404.html, and templates/500.html.
Custom Error Pages | 29
Example 3-7. templates/base.html: Base application template with navigation bar
{% extends "bootstrap/base.html" %}
{% block title %}Flasky{% endblock %}
{% block navbar %}
<div class="navbar navbar-inverse" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle"
data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">Flasky</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a href="/">Home</a></li>
</ul>
</div>
</div>
</div>
{% endblock %}
{% block content %}
<div class="container">
{% block page_content %}{% endblock %}
</div>
{% endblock %}
In the content block of this template is just a container <div> element that wraps a new
empty block called page_content, which derived templates can define.
The templates of the application will now inherit from this template instead of directly
from Flask-Bootstrap. Example 3-8 shows how simple it is to construct a custom code
404 error page that inherits from templates/base.html.
Example 3-8. templates/404.html: Custom code 404 error page using template inheri‐
tance
{% extends "base.html" %}
{% block title %}Flasky - Page Not Found{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>Not Found</h1>
30 | Chapter 3: Templates
Exploring the Variety of Random
Documents with Different Content
trenches running towards the enemy's position. These are connected
by transversal trenches, the purpose being to get one's own position
always closer to the enemy's. As soon as one's position has
approached near enough to make it possible to throw hand grenades
into the enemy's position the hand grenade sections have to take up
their places and bombard the enemy's trenches continually with
hand grenades, day and night.
Some few hundred yards to the rear are the heavy modern mine
throwers firing a projectile weighing 140 pounds. Those projectiles,
which look like sugar loaves, fly cumbrously over to the enemy
where they do great damage. The trade of war must not stop at
night; so the darkness is made bright by means of illuminating
rockets. The illuminating cartridge is fired from a pistol, and for a
second all is bright as day. As all that kind of work was done by
sappers the French hated the sappers especially, and French
prisoners often told us that German prisoners with white buttons
and black ribbons on their caps (sappers) would be treated without
any mercy. Warned by the statements of those prisoners nearly all
provided themselves with infantry uniforms. We knew that we had
gradually become some specialty in the trenches.
If the infantry were molested somewhere by the enemy's hand
grenades they used to come running up to us and begged us to go
and meet the attack. Each of us received a cigar to light the hand
grenades, and then we were off. Ten or twenty of us rained hand
grenades on the enemy's trench for hours until one's arm got too
stiff with throwing.
Thus the slaughter continued, day after day, night after night. We
had 48 hours in the trenches and 12 hours' sleep. It was found
impossible to divide the time differently, for we were too few. The
whole of the forest had been shot and torn to tatters. The artillery
was everywhere and kept the villages behind the enemy's position
under fire. Once one of the many batteries which we always passed
on our way from camp to the front was just firing when we came by.
I interrogated one of the sighting gunners what their target might
be. "Some village or other," the gunner replied. The representative
of the leader of the battery, a lieutenant-colonel, was present. One
of my mates inquired whether women and children might not be in
the villages. "That's neither here nor there," said the lieutenant-
colonel, "the women and children are French, too, so what's the
harm done? Even their litter must be annihilated so as to knock out
of that nation for a hundred years any idea of war."
If that "gentleman" thought to win applause he was mistaken. We
went our way, leaving him to his "enjoyment."
On that day an assault on the enemy's position had been ordered,
and we had to be in our places at seven o'clock in the morning. The
67th regiment was to attack punctually at half past eight, the
sappers taking the lead. The latter had been provided with hand
grenades for that purpose. We were only some twenty yards away
from the enemy. Those attacks, which were repeated every week,
were prepared by artillery fire half an hour before the assault began.
The artillery had to calculate their fire very carefully, because the
distance between the trench and that of the enemy was very small.
That distance varied from three to a hundred yards, it was nowhere
more than that. At our place it was twenty yards. Punctually at eight
o'clock the artillery began to thunder forth. The first three shots
struck our own trench, but those following squarely hit the mark,
i.e., the French trench. The artillery had got the exact range and
then the volleys of whole batteries began to scream above our
heads. Every time the enemy's trench or the roads leading to it were
hit with wonderful accuracy. One could hear the wounded cry, a sign
that many a one had already been crippled. An artillery officer made
observations in the first trench and directed the fire by telephone.
The artillery became silent exactly at half past eight, and we passed
to the assault. But the 11th company of regiment No. 67, of which I
spoke before, found itself in a such a violent machine-gun fire that
eighteen men had been killed a few paces from our trench. The
dead and wounded had got entangled in the wild jumble of the trees
and branches encumbering the ground. Whoever could run tried to
reach the enemy's trench as quickly as possible. Some of the enemy
defended themselves desperately in their trench, which was filled
with mud and water, and violent hand to hand fighting ensued. We
stood in the water up to our knees, killing the rest of our opponents.
Seriously wounded men were lying flat in the mud with only their
mouths and noses showing above the water. But what did we care!
They were stamped deeper in the mud, for we could not see where
we were stepping; and so we rolled up the whole trench. Thereupon
the conquered position was fortified as well as it could be done in all
haste. Again we had won a few yards of the Argonnes at the price of
many lives. That trench had changed its owners innumerable times
before, a matter of course in the Argonnes, and we awaited the
usual counter attack.
Presently the "mules" began to get active. "Mules" are the guns of
the French mountain artillery. As those guns are drawn by mules,
the soldier in the Argonnes calls them "mules" for short. They are
very light guns with a flat trajectory, and are fired from a distance of
only 50-100 yards behind the French front. The shells of those guns
whistled above our heads. Cutting their way through the branches
they fly along with lightning rapidity to explode in or above some
trench. In consequence of the rapid flight and the short distance the
noise of the firing and the explosion almost unite in a single bang.
Those "mules" are much feared by the German soldiers, because
those guns are active day and night. Thus day by day we lived
through the same misery.
XIX
CHRISTMAS IN THE TRENCHES
Winter had arrived and it was icy cold. The trenches, all of which
had underground water, had been turned into mere mud holes. The
cold at night was intense, and we had to do 48 hours' work with 12
hours' sleep. Every week we had to make an attack the result of
which was in no proportion to the immense losses. During the entire
four months that I was in the Argonnes we had a gain of terrain
some 400 yards deep. The following fact will show the high price
that was paid in human life for that little piece of France. All the
regiments (some of these were the infantry regiments Nos. 145, 67,
173, and the Hirschberg sharpshooting battalion No. 5) had their
own cemetery. When we were relieved in the Argonnes there were
more dead in our cemetery than our regiment counted men. The
67th regiment had buried more than 2000 men in its cemetery, all of
whom, with the exception of a few sappers, had belonged to
regiment No. 67. Not a day passed without the loss of human lives,
and on a "storming day" death had an extraordinarily rich harvest.
Each day had its victims, sometimes more, sometimes fewer. It must
appear quite natural that under such conditions the soldiers were
not in the best of moods. The men were all completely stupefied.
Just as they formerly went to work regularly to feed the wife and
children they now went to the trenches in just the same regular way.
That business of slaughtering and working had become an every day
affair. When they conversed it was always the army leaders, the
Crown Prince and Lieutenant-General von Mudra, the general in
command of the 16th Army Corps, that were most criticized.
The troops in the Argonnes belonged to the 16th Army Corps, to the
33rd and 34th division of infantry. Neither of the two leaders, neither
the Crown Prince nor von Mudra, have I ever seen in the trenches.
The staff of the Crown Prince had among its members the old
General-Fieldmarshal Count von Haeseler, the former commander of
the 16th Army Corps, a man who in times of peace was already
known as a relentless slave driver. The "triplets," as we called the
trio, the Crown Prince, von Mudra, and Count von Haeseler, were
more hated by most of the soldiers than the Frenchman who was
out with his gun to take our miserable life.
Many miles behind the front the scion of the Hohenzollerns found no
difficulty to spout his "knock them hard!" and, at the price of
thousands of human lives, to make himself popular with the patriots
at home who were sitting there behind the snug stove or at the beer
table complaining that we did not advance fast enough. Von Mudra
got the order "Pour le merite"; they did not think of his soldiers who
had not seen a bed, nor taken off their trousers or boots for months;
these were provided with food—and shells, and were almost being
eaten up by vermin.
That we were covered with body lice was not to be wondered at, for
we had scarcely enough water for drinking purposes, and could not
think of having a wash. We had worn our clothes for months without
changing them; the hair on our heads and our beards had grown to
great length. When we had some hours in which to rest, the lice
would not let us sleep.
The air in the shelters was downright pestiferous, and to that foul
stench of perspiration and putrefaction was added the plague of lice.
At times one was sitting up for hours and could not sleep, though
one was dead tired. One could catch lice, and the more one caught
the worse they got. We were urgently in want of sleep, but it was
impossible to close the eyes on account of the vermin. We led a
loathsome, pitiful life, and at times we said to one another that
nobody at home even suspected the condition we were in. We often
told one another that if later on we should relate to our families the
facts as they really were they would not believe them. Many soldiers
tried to put our daily experience in verse.
There were many of such jingles illustrating our barbarous
handicraft.
It was in the month of December and the weather was extremely
cold. At times we often stood in the trenches with the mud running
into our trousers' pockets. In those icy cold nights we used to sit in
the trenches almost frozen to a lump of ice, and when utter
exhaustion sometimes vanquished us and put us to sleep we found
our boots frozen to the ground on waking up. Quite a number of
soldiers suffered from frost-bitten limbs; it was mostly their toes that
were frost-bitten. They had to be taken to the hospital. The soldiers
on duty fired incessantly so as to keep their fingers warm.
Not all the soldiers are as a rule kept ready to give battle. If no
attack is expected or intended, only sentries occupy the trench.
About three yards apart a man is posted behind his protective shield
of steel. Nevertheless all the men are in the trench. The sentries
keep their section under a continual fire, especially when it is cold
and dark. The fingers get warm when one pulls the trigger. Of
course, one cannot aim in the darkness, and the shots are fired at
random. The sentry sweeps his section so that no hostile patrol can
approach, for he is never safe in that thicket. Thus it happens that
the firing is generally more violent at night than at day; but there is
never an interval. The rifles are fired continually; the bullets keep
whistling above our trench and patter against the branches. The
mines, too, come flying over at night, dropping at a high angle.
Everybody knows the scarcely audible thud, and knows at once that
it is a mine without seeing anything. He warns the others by calling
out, "Mine coming!" and everybody looks in the darkness for the
"glow-worm," i.e., the burning fuse of the mine. The glowing fuse
betrays the direction of the mine, and there are always a few short
seconds left to get round some corner. The same is the case with the
hand grenades. They, too, betray the line of their flight at night by
their burning fuse. If they do not happen to arrive in too great
numbers one mostly succeeds in getting out of their way. In daylight
that is not so hard because one can overlook everything. It often
happens that one cannot save oneself in time from the approaching
hand grenade. In that case there is only one alternative—either to
remain alive or be torn to atoms. Should a hand grenade suddenly
fall before one's feet one picks it up without hesitation as swiftly as
possible and throws it away, if possible back into the enemy's trench.
Often, however, the fuse is of such a length that the grenade does
not even explode after reaching the enemy's trench again, and the
Frenchman throws it back again with fabulous celerity. In order to
avoid the danger of having a grenade returned the fuse is made as
short as possible, and yet a grenade will come back now and again
in spite of all. To return a grenade is of course dangerous work, but
a man has no great choice; if he leaves the grenade where it drops
he is lost, as he cannot run away; and he knows he will be crushed
to atoms, and thus his only chance is to pick up the grenade and
throw it away even at the risk of having the bomb explode in his
hand. I know of hand grenades thrown by the French that flew
hither and thither several times. One was thrown by the French and
immediately returned; it came back again in an instant, and again
we threw it over to them; it did not reach the enemy's trench that
time, but exploded in the air.
Though in general the infantry bullets cannot do much damage while
one is in the trench it happens daily that men are killed by ricochet
bullets. The thousands of bullets that cut through the air every
minute all pass above our heads. But some strike a tree or branch
and glance off. If in that case they hit a man in the trench they
cause terrible injuries, because they do not strike with their heads
but lengthwise. Whenever we heard of dum-dum bullets we thought
of those ricochet bullets, though we did not doubt that there were
dum-dum bullets in existence. I doubt, however, if dum-dum bullets
are manufactured in factories, for the following reasons:—first,
because a dum-dum bullet can easily damage the barrel of a rifle
and make it useless; secondly, because the average soldier would
refuse to carry such ammunition, for if a man is captured and such
bullets are found on him, the enemy in whose power he is would
punish him by the laws of war as pitilessly as such an inhuman
practice deserves to be punished. Generally, of course, a soldier only
executes his orders.
However, there exist dum-dum bullets, as I mentioned before. They
are manufactured by the soldiers themselves. If the point is filed or
cut off a German infantry bullet, so that the nickel case is cut
through and the lead core is laid bare, the bullet explodes when
striking or penetrating an object. Should a man be hit in the upper
arm by such a projectile the latter, by its explosive force, can mangle
the arm to such an extent that it only hangs by a piece of skin.
Christmas came along, and we still found ourselves at the same
place without any hope of a change. We received all kinds of gifts
from our relations at home and other people. We were at last able to
change our underwear which we had worn for months.
Christmas in the trenches! It was bitterly cold. We had procured a
pine tree, for there were no fir trees to be had. We had decorated
the tree with candles and cookies, and had imitated the snow with
wadding.
Christmas trees were burning everywhere in the trenches, and at
midnight all the trees were lifted on to the parapet with their burning
candles, and along the whole line German soldiers began to sing
Christmas songs in chorus. "O, thou blissful, O, thou joyous, mercy
bringing Christmas time!" Hundreds of men were singing the song in
that fearful wood. Not a shot was fired; the French had ceased firing
along the whole line. That night I was with a company that was only
five paces away from the enemy. The Christmas candles were
burning brightly, and were renewed again and again. For the first
time we heard no shots. From everywhere, throughout the forest,
one could hear powerful carols come floating over—"Peace on earth
—"
The French left their trenches and stood on the parapet without any
fear. There they stood, quite overpowered by emotion, and all of
them with cap in hand. We, too, had issued from our trenches. We
exchanged gifts with the French—chocolate, cigarettes, etc. They
were all laughing, and so were we; why, we did not know. Then
everybody went back to his trench, and incessantly the carol
resounded, ever more solemnly, ever more longingly—"O, thou
blissful—"
All around silence reigned; even the murdered trees seemed to
listen; the charm continued, and one scarcely dared to speak. Why
could it not always be as peaceful? We thought and thought, we
were as dreamers, and had forgotten everything about us.—
Suddenly a shot rang out; then another one was fired somewhere.
The spell was broken. All rushed to their rifles. A rolling fire. Our
Christmas was over.
We took up again our old existence. A young infantryman stood next
to me. He tried to get out of the trench. I told him: "Stay here; the
French will shoot you to pieces." "I left a box of cigars up there, and
must have it back." Another one told him to wait till things quieted
down somewhat. "They won't hit me; I have been here three
months, and they never caught me yet." "As you wish; go ahead!"
Scarcely had he put his head above the parapet when he tumbled
back. Part of his brains was sticking to my belt. His cap flew high up
into the air. His skull was shattered. He was dead on the spot. His
trials were over. The cigars were later on fetched by another man.
On the following Christmas day an army order was read out. We
were forbidden to wear or have in our possession things of French
origin; for, every soldier who was found in possession of such things
would be put before a court-martial as a marauder by the French if
they captured him. We were forbidden to use objects captured from
the French, and we were especially forbidden to make use of woolen
blankets, because the French were infected with scabies. Scabies is
an itching skin disease, which it takes at least a week to cure. But
the order had a contrary effect. If one was the owner of such an
"itch-blanket" one had a chance of getting into the hospital for some
days. The illness was not of a serious nature, and one was at least
safe from bullets for a few days. Every day soldiers were sent to the
hospital, and we, too, were watching for a chance to grab such a
French blanket. What did a man care, if he could only get out of that
hell!
XX
THE "ITCH"—A SAVIOR
On January 5th the Germans attacked along the whole forest front,
and took more than 1800 prisoners. We alone had captured 700
men of the French infantry regiment No. 120. The hand to hand
fighting lasted till six o'clock at night. On that day I, together with
another sapper, got into a trench section that was still being
defended by eight Frenchmen. We could not back out, so we had to
take up the unequal struggle. Fortunately we were well provided
with hand grenades. We cut the fuses so short that they exploded at
the earliest moment. I threw one in the midst of the eight
Frenchmen. They had scarcely escaped the first one, when the
second arrived into which they ran. We utilized their momentary
confusion by throwing five more in quick succession. We had
reduced our opponents to four. Then we opened a rifle fire, creeping
closer and closer up to them. Their bullets kept whistling above our
heads. One of the Frenchmen was shot in the mouth; three more
were left. These turned to flee. In such moments one is seized with
an indescribable rage and forgets all about the danger that
surrounds one. We had come quite near to them, when the last one
stumbled and fell forward on his face. In a trice I was on him; he
fought desperately with his fists; my mate was following the other
two. I kept on wrestling with my opponent. He was bleeding from
his mouth; I had knocked out some of his teeth. Then he
surrendered and raised his hands. I let go and then had a good look
at him. He was some 35 years old, about ten years older than
myself. I now felt sorry for him. He pointed to his wedding ring,
talking to me all the while. I understood what he wanted—he
wanted to be kept alive. He handed me his bottle, inviting me to
drink wine. He cried; maybe he thought of his wife and children. I
pressed his hand, and he showed me his bleeding teeth. "You are a
silly fellow," I told him; "you have been lucky. The few missing teeth
don't matter. For you the slaughtering is finished; come along!" I
was glad I had not killed him, and took him along myself so as to
protect him from being ill-treated. When I handed him over he
pressed my hand thankfully and laughed; he was happy to be safe.
However bad the time he might have as prisoner he would be better
off at any rate than in the trenches. At least he had a chance of
getting home again.
In the evening we took some of the forbidden blankets, hundreds of
which we had captured that day. Ten of us were lying in a shelter, all
provided with blankets. Everybody wanted to get the "itch," however
strange that may sound. We undressed and rolled ourselves in those
blankets. Twenty-four hours later little red pimples showed
themselves all over the body, and twelve men reported sick. The
blankets were used in the whole company, but all of them had not
the desired effect. The doctor sent nine of us to the hospital at
Montmédy, and that very evening we left the camp in high glee. The
railroad depot at Apremont had been badly shelled; the next station
was Chatel. Both places are a little more than three miles behind the
front. At Apremont the prisoners were divided into sections. Some of
the prisoners had their homes at Apremont. Their families were still
occupying their houses, and the prisoners asked to be allowed to
pay them a visit. I chanced to observe one of those meetings at
Apremont. Two men of the landstrum led one of the prisoners to the
house which he pointed out to them as his own. The young wife of
the prisoner was sitting in the kitchen with her three children. We
followed the men into the house. The woman became as white as a
sheet when she beheld her husband suddenly. They rushed to meet
each other and fell into each other's arms. We went out, for we felt
that we were not wanted. The wife had not been able to get the
slightest signs from her husband for the last five months, for the
German forces had been between her and him. He, on the other
hand, had been in the trench for months knowing that his wife and
children must be there, on the other side, very near, yet not to be
reached. He did not know whether they were alive or dead. He
heard the French shells scream above his head. Would they hit
Apremont? He wondered whether it was his own house that had
been set alight by a shell and was reddening the sky at night. He did
not know. The uncertainty tortured him, and life became hell. Now
he was at home, though only for a few hours. He had to leave again
a prisoner; but now he could send a letter to his wife by the field
post. He had to take leave. She had nothing she could give him—no
underwear, no food, absolutely nothing. She had lost all and had to
rely on the charity of the soldiers. She handed him her last money,
but he returned it. We could not understand what they told each
other. She took the money back; it was German money, five and ten
pfennig pieces and some coppers—her whole belongings. We could
no longer contain ourselves and made a collection among ourselves.
We got more than ten marks together which we gave to the young
woman. At first she refused to take it and looked at her husband.
Then she took it and wanted to kiss our hands. We warded her off,
and she ran to the nearest canteen and bought things. Returning
with cigars, tobacco, matches, and sausage, she handed all over to
her husband with a radiant face. She laughed, once again perhaps in
a long time, and sent us grateful looks. The children clung round
their father and kissed him again and again. She accompanied her
husband, who carried two of the kiddies, one on each arm, while his
wife carried the third child. Beaming with happiness the family
marched along between the two landsturm men who had their
bayonets fixed. When they had to take leave, all of them, parents
and children began to weep. She knew that her husband was no
longer in constant danger, and she was happy, for though she had
lost much, she still had her most precious possessions.
Thousands of poor men and women have met such a fate near their
homes.
Regular trains left Chatel. We quitted the place at 11 o'clock at night,
heartily glad to leave the Argonnes behind us. We had to change
trains at Vouzières, and took the train to Diedenhofen. There we saw
twelve soldiers with fixed bayonets take along three Frenchmen.
They were elderly men in civilian dress. We had no idea what it
signified, so we entered into a conversation with one of our fellow
travelers. He was a merchant, a Frenchman living at Vouzières, and
spoke German fluently. The merchant was on a business trip to
Sédan, and told us that the three civilian prisoners were citizens of
his town. He said: "We obtain our means of life from the German
military authorities, but mostly we do not receive enough to live, and
the people have nothing left of their own; all the cattle and food
have been commandeered. Those three men refused to keep on
working for the military authorities, because they could not live on
the things they were given. They were arrested and are now being
transported to Germany. Of course, we don't know what will happen
to them."
The man also told us that all the young men had been taken away
by the Germans; all of them had been interned in Germany.
At Sédan we had to wait for five hours; for hospital trains were
constantly arriving. It was 2 o'clock in the afternoon of the following
day when we reached Montmédy, where we went to the hospital.
There all our clothes were disinfected in the "unlousing
establishment," and we could take a proper bath. We were lodged in
the large barracks. There one met people from all parts of the front,
and all of them had only known the same misery; there was not one
among them who did not curse this war. All of them were glad to be
in safety, and all of them tried their best to be "sick" as long as
possible. Each day we were twice treated with ointment; otherwise
we were at liberty to walk about the place.
One day we paid a visit to the fortress of Montmédy high up on a
hill. Several hundreds of prisoners were just being fed there. They
were standing about in the yard of the fortress and were eating their
soup. One of the prisoners came straight up to me. I had not noticed
him particularly, and recognized him only when he stood before me.
He was the man I had struggled with on January 5th, and we
greeted each other cordially. He had brought along a prisoner who
spoke German well and who interpreted for us all we had to say to
each other. He had seen me standing about and had recognized me
at once. Again and again he told me how glad he was to be a
prisoner. Like myself he was a soldier because he had to be, and not
from choice. At that time we had fought with each other in blind
rage; for a moment we had been deadly enemies. I felt happy at
having stayed my fury at that time, and again I became aware of the
utter idiocy of that barbarous slaughter. We separated with a firm
handshake.
A fortnight I remained at the hospital; then I had to return to the
front. We had been treated well at the hospital, so we started on our
return journey with mixed feelings. As soon as we arrived at Chatel,
the terminus, we heard the incessant gun fire. It was no use kicking,
we had to go into the forest again. When we reached our old camp,
we found that different troops were occupying it. Our company had
left, nobody knew for what destination. Wherever we asked, nobody
could give us any information. So we had to go back to the
command of our corps, the headquarters of which were at Corney at
that time. We left Chatel again by a hospital train, and reached
Corney after half an hour's journey. Corney harbored the General
Staff of the 16th Army Corps, and we thought they surely ought to
know where our company was. General von Mudra and his officers
had taken up their quarters in a large villa. The house was guarded
by three double sentries. We showed our pay books and hospital
certificates, and an orderly led us to a spacious room. It was the
telephone room. There the wires from all the divisional fronts ran
together, and the apparatus were in constant use. A sergeant-major
looked into the lists and upon the maps. In two minutes he had
found our company. He showed us on the map where it was fighting
and where its camp was. "The camp is at the northern end of
Verennes," he said, "and the company belongs to the 34th division;
formerly it was part of the 33rd. The position it is in is in the villages
of Vauquois and Boureuilles." Then he explained to us on the map
the direction we were to take, and we could trot off. We returned by
rail to Chatel, and went on foot from there to Apremont. We spent
the night in the half destroyed depot of Apremont. In order to get to
Varennes we had to march to the south. On our way we saw French
prisoners mending the roads. Most of them were black colonial
troops in picturesque uniforms. On that road Austrian motor
batteries were posted. Three of those 30.5-cm. howitzers were
standing behind a rocky slope, but did not fire. When at noon we
reached the height of Varennes we saw the whole wide plan in front
of us. Varennes itself was immediately in front of us in the valley. A
little farther up on the heights was Vauquois. No houses were to be
seen; one could only notice a heap of rubbish through the field
glasses. Shells kept exploding in that rubbish heap continually, and
we felt a cold sweat run down our backs at the thought that the
place up there was our destination. We had scarcely passed the
ridge when some shells exploded behind us. At that place the French
were shooting with artillery at individuals. As long as Vauquois had
been in their power they had been able to survey the whole country,
and we comprehended why that heap of rubbish was so bitterly
fought for. We ran down the slope and found ourselves in Varennes.
The southern portion of the village had been shelled to pieces and
gutted. Only most of the chimneys which were built apart from the
bottom upward, had remained standing, thin blackened forms rising
out of the ruins into the air. Everywhere we saw groups of soldiers
collecting the remaining more expensive metals which were sent to
Germany. Among other things church-bells melted into shapeless
lumps were also loaded on wagons and taken away. All the copper,
brass, tin, and lead that could be got was collected.
XXI
IN THE HELL OF VAUQUOIS
We soon found our company, and our comrades told us what hell
they had gotten into. The next morning our turn came, too. We had
to reach the position before day-break, for as soon as it got light the
French kept all approaches under constant fire. There was no trace
of trenches at Vauquois. All that could be seen were pieces of
stones. Not a stone had literally remained on the other at Vauquois.
That heap of ruins, once a village, had changed hands no less than
fifteen times. When we arrived half of the place was in the
possession of the Germans. But the French dominated the highest
point, whence they could survey the whole country for many miles
around. In the absence of a trench we sought cover behind stones,
for it was absolutely impossible to construct trenches; the artillery
was shooting everything to pieces.
Thus the soldiers squatted behind piles of stones and fired as fast as
their rifles would allow. Guns of all sizes were bombarding the village
incessantly. There was an army of corpses, Frenchmen and
Germans, all lying about pell-mell. At first we thought that that
terrible state of things was only temporary, but after a few days we
recognized that a slaughter worse than madness was a continuous
state of things at that place. Day and night, ever the same. With
Verdun as a base of operations the French continually brought up
fresh masses of troops. They had carried along a field railroad the
heavy pieces of the neighboring forts of Verdun, and in the spring of
1915 an offensive of a local, but murderous kind was begun. The
artillery of both sides bombarded the place to such an extent that
not a foot of ground could be found that was not torn up by shells.
Thousands upon thousands of shells of all sizes were employed. The
bombardment from both sides lasted three days and three nights,
until at last not a soldier, neither French nor German, was left in the
village. Both sides had been obliged to retreat before the infernal fire
of the opponent, for not a man would have escaped alive out of that
inferno. The whole slope and height were veiled in an impenetrable
smoke. In the evening of the third day the enemy's bombardment
died down a little, and we were ordered to go forward again into the
shell torn ruins. It was not yet quite dark when the French advanced
in close order.
We were in possession of almost the whole of the village, and had
placed one machine-gun next to the other. We could see the
projectiles of the artillery burst in great numbers among the reserves
of the attackers. Our machine-guns literally mowed down the first
ranks. Five times the French renewed their attack during that night,
their artillery meanwhile making great gaps in our ranks. We soldiers
calculated that the two sides had together some three or four
thousand men killed in that one night. Next morning the French
eased their attacks, and their guns treated us again to the
accustomed drum fire. We stood it until 10 o'clock in the morning;
then we retreated again without awaiting orders, leaving
innumerable dead men behind. Again the French advanced in the
face of a violent German artillery fire, and effected a lodgment at the
northern edge of the village of Vauquois that used to be. A few piles
of stones was all that still belonged to us. We managed to put a few
stones before us as a protection. The guns of neither side could hurt
us or them, for they, the enemy, were but ten paces away. But the
country behind us was plowed by projectiles. In face of the machine
gun fire it was found impossible to bring up ammunition.
The sappers undid the coils of rope worn round their bodies, and
three men or more crept back with them. One of them was killed;
the others arrived safely and attached the packets of cartridges to
the rope. Thus we brought up the ammunition by means of a rope
running in a circle, until we had enough or till the rope was shot
through. At three o'clock in the afternoon we attacked again, but
found it impossible to rise from the ground on account of the hail of
bullets. Everybody was shouting, "Sappers to the front with hand
grenades!" Not a sapper stirred. We are only human, after all.
A sergeant-major of the infantry came creeping up. He looked as if
demented, his eyes were bloodshot. "You're a sapper?" "Yes,"
"Advance!" "Alone?" "We're coming along!" We had to roar at each
other in order to make ourselves understood in the deafening,
confounded row. Another sapper lay beside me. When the sergeant-
major saw that he could do nothing with me he turned to the other
fellow. That man motioned to him to desist, but the sergeant-major
got ever more insistent, until the sapper showed him his dagger, and
then our superior slung his hook. Some twenty hand grenades were
lying in front of us. Ten of them I had attached to my belt for all
emergencies. I said to myself that if all of them exploded there
would not be much left of me. I had a lighted cigar in my mouth. I
lit one bomb after the other and threw them over to some
Frenchmen who were working a machine-gun in front of me, behind
a heap of stones. All around me the bullets of the machine-guns
were splitting the stones. I had already thrown four grenades, but all
of them had overshot the mark. I took some stones and threw them
to find out how far I would have to throw in order to hit the fire
spitting machine in front. My aim got more accurate each time until I
hit the barrel of the gun. "If it had only been a hand grenade," I
thought. An infantryman close to me was shot through the shell of
one ear, half of which was cut in pieces; the blood was streaming
down his neck. I had no more material for bandaging except some
wadding, which I attached to his wound. In my pocket I had a roll of
insulating ribbon, rubber used to insulate wires; with that I
bandaged him. He pointed to the machine-gun. Thereupon I gave
him my cigar, telling him to keep it well alight so as to make the fuse
which I desired to light by it burn well. In quick succession I threw
six hand grenades. I don't know how many of them took effect, but
the rags of uniforms flying about and a demolished machine-gun
said enough. When we advanced later on I observed three dead
men lying round the machine-gun.
That was only one example of the usual, daily occurrences that
happen day and night, again and again and everywhere, and the
immense number of such actions of individual soldiers makes the
enormous loss of human life comprehensible.
We were still lying there without proceeding to the attack. Again
ammunition was brought up by ropes from the rear. A hand grenade
duel ensued; hundreds of hand grenades were thrown by both sides.
Things could not go on long like that; we felt that something was
bound to happen. Without receiving an order and yet as if by
command we all jumped up and advanced with the dagger in our
hands right through the murderous fire, and engaged in the
maddest hand to hand fighting. The daggers, sharp as razors, were
plunged into head after head, chest after chest. One stood on
corpses in order to make other men corpses. New enemies came
running up. One had scarcely finished with one when three more
appeared on the scene.
We, too, got reinforcements. One continued to murder and expected
to be struck down oneself the next moment. One did not care a cent
for one's life, but fought like an animal. I stumbled and fell on the
stones. At that very moment I caught sight of a gigantic Frenchman
before me who was on the point of bringing his sapper's spade down
on me. I moved aside with lightning speed, and the blow fell upon
the stone. In a moment my dagger was in his stomach more than up
to the hilt. He went down with a horrible cry, rolling in his blood in
maddening pain. I put the bloody dagger back in my boot and took
hold of the spade. All around me I beheld new enemies. The spade I
found to be a handy weapon. I hit one opponent between head and
shoulder. The sharp spade half went through the body; I heard the
cracking of the bones that were struck. Another enemy was close to
me. I dropped the spade and took hold of my dagger again. All
happened as in a flash. My opponent struck me in the face, and the
blood came pouring out of my mouth and nose. We began to wrestle
with each other. I had the dagger in my right hand. We had taken
hold of each other round the chest. He was no stronger than myself,
but he held me as firmly as I held him. We tried to fight each other
with our teeth. I had the dagger in my hand, but could not strike.
Who was it to be? He or I? One of us two was sure to go down. I
got the dagger in such a position that its point rested on his back.
Then I pressed his trembling body still more firmly to myself. He
fastened his teeth in my shaggy beard, and I felt a terrible pain. I
pressed him still more firmly so that his ribs almost began to crack
and, summoning all my strength, I pushed the dagger into the right
side of his back, just below the shoulderblade. In frightful pain he
turned himself round several times, fell on his face, and lay groaning
on the ground. I withdrew my dagger; he bled to death like many
thousands.
We had pushed back the French for some yards when we received
strong assistance. After a short fight the enemy turned and fled, and
we followed him as far as the southern edge of the village. There
the French made a counterattack with fresh bodies of men and
threw us back again for some 50 yards. Then the attack was halted,
and we found ourselves again where we had been at the beginning
of that four days' slaughter. Thousands of corpses were covering the
ruins of Vauquois, all sacrificed in vain.
XXII
SENT ON FURLOUGH
For four days and nights, without food and sleep, we had been
raging like barbarians, and had spent all our strength. We were soon
relieved. To our astonishment we were relieved by cavalry. They
were Saxon chasseurs on horseback who were to do duty as
infantrymen. It had been found impossible to make good the
enormous losses of the preceding days by sending up men of the
depot. So they had called upon the cavalry who, by the way, were
frequently employed during that time. The soldiers who had been in
a life and death struggle for four days were demoralized to such an
extent that they had no longer any fighting value. We were relieved
very quietly, and could then return to our camp. We did not hear
before the next day that during the period described our company
had suffered a total loss of 49 men. The fate of most of them was
unknown; one did not know whether they were dead or prisoners or
whether they lay wounded in some ambulance station.
The village of Varennes was continually bombarded by French guns
of large size. Several French families were still living in a part of the
village that had not been so badly damaged. Every day several of
the enemy's 28-cm. shells came down in that quarter. Though many
inhabitants had been wounded by the shells the people could not be
induced to leave their houses.
Our quarters were situated near a very steep slope and were thus
protected against artillery fire. They consisted of wooden shanties
built by ourselves. We had brought up furniture from everywhere
and had made ourselves at home; for Varennes was, after all, nearly
two miles behind the front. But all the shanties were not occupied,
for the number of our men diminished from day to day. At last the
longed-for men from the depot arrived. Many new sapper formations
had to be got together for all parts of the front, and it was therefore
impossible to supply the existing sapper detachments with their
regular reserves. Joyfully we greeted the new arrivals. They were, as
was always the case, men of very different ages; a young boyish
volunteer of 17 years would march next to an old man of the
landsturm who had likewise volunteered. All of them, without any
exception, have bitterly repented of their "free choice" and made no
secret of it. "It's a shame," a comrade told me, "that those
seventeen-year-old children should be led to the slaughter, and that
their young life is being poisoned, as it needs must be in these
surroundings; scarcely out of boyhood, they are being shot down
like mad dogs."
It took but a few days for the volunteers—all of them without an
exception—to repent bitterly of their resolve, and every soldier who
had been in the war for any length of time would reproach them
when they gave expression to their great disappointment. "But you
have come voluntarily," they were told; "we had to go, else we
should have been off long ago." Yet we knew that all those young
people had been under some influence and had been given a wrong
picture of the war.
Those soldiers who had been in the war from the start who had not
been wounded, but had gone through all the fighting, were
gradually all sent home on furlough for ten days. Though our
company contained but 14 unwounded soldiers it was very hard to
obtain the furlough. We had lost several times the number of men
on our muster-roll, but all our officers were still in good physical
condition.
It was not until September that I managed to obtain furlough at the
request of my relations, and I left for home with a resolve that at
times seemed to me impossible to execute. All went well until I got
to Diedenhofen.
As far as that station the railroads are operated by the army
authorities. At Diedenhofen they are taken over by the Imperial
Railroads of Alsace-Lorraine and the Prusso-Hessian State Railroads.
So I had to change, and got on a train that went to Saarbruecken. I
had scarcely taken a seat in a compartment in my dirty and ragged
uniform when a conductor came along to inspect the tickets. Of
course, I had no ticket; I had only a furlough certificate and a pass
which had been handed to me at the field railroad depot of Chatel.
The conductor looked at the papers and asked me again for my
ticket. I drew his attention to my pass. "That is only good for the
territory of the war operations," he said; "you are now traveling on a
state railroad and have to buy a ticket."
I told him that I should not buy a ticket, and asked him to inform
the station manager. "You," I told him, "only act according to
instructions. I am not angry with you for asking of me what I shall
do under no circumstances." He went off and came back with the
manager. The latter also inspected my papers and told me I had to
pay for the journey. "I have no means for that purpose," I told him.
"For these last three years I have been in these clothes" (I pointed
to my uniform), "and for three years I have therefore been without
any income. Whence am I to get the money to pay for this journey?"
"If you have no money for traveling you can't take furlough." I
thought to myself that if they took me deep into France they were in
conscience bound to take me back to where they had fetched me.
Was I to be a soldier for three years and fight for the Fatherland for
more than a year only to find that now they refused the free use of
their railroads to a ragged soldier? I explained that I was not going
to pay, that I could not save the fare from the few pfennigs' pay. I
refused explicitly to pay a soldier's journey with my private money,
even if—as was the case here—that soldier was myself. Finally I told
him, "I must request you to inform the military railroad commander;
the depot command attends to soldiers, not you." He sent me a
furious look through his horn spectacles and disappeared. Two
civilians were sitting in the same compartment with me; they
thought it an unheard-of thing that a soldier coming from the front
should be asked for his fare. Presently the depot commander came
up with a sergeant. He demanded to see my furlough certificate, pay
books, and all my other papers.
"Have you any money?"
"No."
"Where do you come from?"
"From Chatel in the Argonnes."
"How long were you at the front?"
"In the fourteenth month."
"Been wounded?"
"No."
"Have you no money at all?"
"No; you don't want money at the front."
"The fare must be paid. If you can't, the company must pay. Please
sign this paper."
I signed it without looking at it. It was all one to me what I signed,
as long as they left me alone. Then the sergeant came back.
"You can not travel in that compartment; you must also not converse
with travelers. You have to take the first carriage marked 'Only for
the military.' Get into that."
"I see," I observed; "in the dogs' compartment."
He turned round again and said, "Cut out those remarks."
The train started, and I arrived safely home. After the first hours of
meeting all at home again had passed I found myself provided with
faultless underwear and had taken the urgently needed bath. Once
more I could put on the civilian dress I had missed for so long a
time. All of it appeared strange to me. I began to think. Under no
conditions was I going to return to the front. But I did not know how
I should succeed in getting across the frontier. I could choose
between two countries only—Switzerland and Holland. It was no use
going to Switzerland, for that country was surrounded by belligerent
states, and it needed only a little spark to bring Switzerland into the
war, and then there would be no loophole for me. There was only
the nearest country left for me to choose—Holland. But how was I to
get there? There was the rub. I concocted a thousand plans and
discarded them again. Nobody, not even my relatives, must know
about it.
XXIII
THE FLIGHT TO HOLLAND
My furlough soon neared its end; there were only four days left. I
remembered a good old friend in a Rhenish town. My plan was
made. Without my family noticing it I packed a suit, boots, and all
necessities, and told them at home that I was going to visit my
friend. To him I revealed my intentions, and he was ready to help
me in every possible manner.
My furlough was over. I put on my uniform, and my relations were
left in the belief that I was returning to the front. I went, however,
to my friend and changed into civilian clothes. I destroyed my
uniform and arms, throwing the lot into the river near by. Thus
having destroyed all traces, I left and arrived at Cologne after some
criss-cross traveling. Thence I journeyed to Duesseldorf and stayed
at night at an hotel. I had already overstayed my leave several days.
Thousands of thoughts went through my brain. I was fully aware
that I would lose my life if everything did not come to pass
according to the program. I intended to cross the frontier near Venlo
(Holland). I knew, however, that the frontier was closely guarded.
The country round Venlo, the course of the frontier in those parts
were unknown to me; in fact, I was a complete stranger. I made
another plan. I returned to my friend and told him that it was
absolutely necessary for me to get to know the frontier district and
to procure a map showing the terrain. I also informed him that I had
to get hold of a false identification paper. He gave me a landsturm
certificate which was to identify me in case of need. In my note-
book I drew the exact course of the frontier from a railway map, and
then I departed again.
Dead tired, I reached Crefeld that night by the last train. I could not
go on. So I went into the first hotel and hired a room. I wrote the
name that was on the false paper into the register and went to
sleep. At six o'clock in the morning there was a knock at my door.
"Who is there?"
"The police."
"The police?"
"Yes; the political police."
I opened the door.
"Here lives ...? (he mentioned the name in which I had registered).
"Yes."
"Have you any identification papers?"
"If you please," I said, handing him the landsturm certificate.
"Everything in order; pardon me for having disturbed you."
"You're welcome; you're welcome," I hastened to reply, and thought
how polite the police was.
That well-known leaden weight fell from my chest, but I had no
mind to go to sleep again. Whilst I was dressing I heard him visit all
the guests of the hotel. I had not thought of the customary
inspection of strangers in frontier towns. It was a good thing I had
been armed for that event.
Without taking breakfast (my appetite had vanished) I went to the
depot and risked traveling to Kempten in spite of the great number
of policemen that were about. I calculated by the map that the
frontier was still some fifteen miles away. I had not much baggage
with me, only a small bag, a raincoat and an umbrella. I marched
along the country road and in five hours I reached the village of
Herongen. To the left of that place was the village of Niederhofen.
Everywhere I saw farmers working in the fields. They would have to
inform me of how the line of the frontier ran and how it was being
watched. In order to procure that information I selected only those
people who, to judge by their appearance, were no "great lights of
the church."
Without arousing suspicion I got to know that the names of the two
places were "Herongen" and "Niederhofen," and that a troop of
cuirassiers were quartered at Herongen. The man told me that the
soldiers were lodged in the dancing hall of the Schwarz Inn.
Presently I met a man who was cutting a hedge. He was a Hollander
who went home across the frontier every night; he had a passport.
"You are the man for me," I thought to myself, and said aloud that I
had met several Hollanders in that part of the country (he was the
first one), and gave him a cigar. I mentioned to him that I had
visited an acquaintance in the Schwarz Inn at Herongen.
"Yes," he said; "they are there."
"But my friend had to go on duty, so I am having a look round."
"They have got plenty to do near the frontier."
"Indeed?"
"Every thirty minutes and oftener a cavalry patrol, and every quarter
of an hour an infantry patrol go scouting along the frontier."
"And how does the frontier run?" I queried, offering him a light for
his cigar.
He showed me with his hand.
"Here in front of you, then right through the woods, then up there;
those high steeples towering over the woods belong to the factories
of Venlo."
I knew enough. After a few remarks I left him. All goes according to
my program, I thought. But there was a new undertaking before me.
I had to venture close enough to the frontier to be able to watch the
patrols without being seen by them. That I succeeded in doing
during the following night.
I hid in the thick underwood; open country was in front of me. I
remained at that spot for three days and nights. It rained and at
night it was very chilly. On the evening of the third day I resolved to
execute my plan that night.
Regularly every fifteen minutes a patrol of from three to six soldiers
arrived. When it had got dark I changed my place for one more to
the right, some five hundred yards from the frontier. I said to myself
that I would have to venture out as soon as it got a little lighter. In
the darkness I could not see anything. It would have to be done in
twilight. I had rolled my overcoat into a bundle to avoid making a
noise against the trees. I advanced just after a patrol had passed. I
went forward slowly and stepped out cautiously without making a
noise. Then I walked with ever increasing rapidity. Suddenly a patrol
appeared on my right. The frontier was about three hundred yards
away from me. The patrol had about two hundred yards to the point
of the frontier nearest to me. Victory would fall to the best and
swiftest runner. The patrol consisted of five men; they fired several
times. That did not bother me. I threw everything away and,
summoning all my strength, I made in huge leaps for the frontier
which I passed like a whirlwind. I ran past the pointed frontier stone
and stopped fifty yards away from it. I was quite out of breath, and
an indescribable happy feeling took hold of me. I felt like crying into
the world that at last I was free.
I seated myself on the stump of a tree and lit a cigar, quite steadily
and slowly; for now I had time. Scarcely fifty yards away, near the
frontier stone, was the disappointed patrol. I read on the side of the
frontier stone facing me, "Koningrjk der Nederlanden" (Kingdom of
the Netherlands). I had to laugh with joy. "Who are you?" one of the
German patrol called to me. "The Hollanders have now the right to
Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.
More than just a book-buying platform, we strive to be a bridge
connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.
Join us on a journey of knowledge exploration, passion nurturing, and
personal growth every day!
ebookbell.com

Flask Web Development 1st Edition Miguel Grinberg

  • 1.
    Flask Web Development1st Edition Miguel Grinberg download https://ebookbell.com/product/flask-web-development-1st-edition- miguel-grinberg-10313190 Explore and download more ebooks at ebookbell.com
  • 2.
    Here are somerecommended products that we believe you will be interested in. You can click the link to download. Flask Web Development Developing Web Applications With Python First Edition Grinberg https://ebookbell.com/product/flask-web-development-developing-web- applications-with-python-first-edition-grinberg-22034586 Flask Web Development Developing Web Applications With Python 2nd Edition Miguel Grinberg https://ebookbell.com/product/flask-web-development-developing-web- applications-with-python-2nd-edition-miguel-grinberg-7316108 Flask Web Development 2nd Edition Miguel Grinberg https://ebookbell.com/product/flask-web-development-2nd-edition- miguel-grinberg-10816962 Flask Web Development Developing Web Applications With Python Miguel Grinberg https://ebookbell.com/product/flask-web-development-developing-web- applications-with-python-miguel-grinberg-48508682
  • 3.
    Flask Web DevelopmentMiguel Grinberg https://ebookbell.com/product/flask-web-development-miguel- grinberg-170883436 Mastering Flask Web Development Second Edition Second Edition Daniel Gaspar https://ebookbell.com/product/mastering-flask-web-development-second- edition-second-edition-daniel-gaspar-7339216 Mastering Flask Web Development Daniel Gaspar Jack Stouffer https://ebookbell.com/product/mastering-flask-web-development-daniel- gaspar-jack-stouffer-49423062 Mastering Flask Web And Api Development 1st Edition Sherwin John C Tragura https://ebookbell.com/product/mastering-flask-web-and-api- development-1st-edition-sherwin-john-c-tragura-58947898 Mastering Flask Web And Api Development Sherwin John C Tragura https://ebookbell.com/product/mastering-flask-web-and-api-development- sherwin-john-c-tragura-74164542
  • 7.
  • 8.
    Flask Web Development byMiguel Grinberg Copyright © 2014 Miguel Grinberg. All rights reserved. Printed in the United States of America. Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472. O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are alsoavailableformosttitles(http://my.safaribooksonline.com).Formoreinformation,contactourcorporate/ institutional sales department: 800-998-9938 or corporate@oreilly.com. Editors: Meghan Blanchette and Rachel Roumeliotis Production Editor: Nicole Shelby Copyeditor: Nancy Kotary Proofreader: Charles Roumeliotis Cover Designer: Randy Comer Interior Designer: David Futato Illustrator: Rebecca Demarest May 2014: First Edition Revision History for the First Edition: 2014-04-25: First release See http://oreilly.com/catalog/errata.csp?isbn=9781449372620 for release details. Nutshell Handbook, the Nutshell Handbook logo, and the O’Reilly logo are registered trademarks of O’Reilly Media,Inc.FlaskWebDevelopment,thepictureofaPyreneanMastiff,andrelatedtradedressaretrademarks of O’Reilly Media, Inc. Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks.Wherethosedesignationsappearinthisbook,andO’ReillyMedia,Inc.wasawareofatrademark claim, the designations have been printed in caps or initial caps. While every precaution has been taken in the preparation of this book, the publisher and authors assume no responsibility for errors or omissions, or for damages resulting from the use of the information contained herein. ISBN: 978-1-449-37262-0 [LSI]
  • 9.
  • 11.
    Table of Contents Preface.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi Part I. Introduction to Flask 1. Installation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Using Virtual Environments 4 Installing Python Packages with pip 6 2. Basic Application Structure. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 Initialization 7 Routes and View Functions 8 Server Startup 9 A Complete Application 9 The Request-Response Cycle 12 Application and Request Contexts 12 Request Dispatching 14 Request Hooks 14 Responses 15 Flask Extensions 16 Command-Line Options with Flask-Script 17 3. Templates. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 The Jinja2 Template Engine 22 Rendering Templates 22 Variables 23 Control Structures 24 Twitter Bootstrap Integration with Flask-Bootstrap 26 Custom Error Pages 29 Links 31 v
  • 12.
    Static Files 32 Localizationof Dates and Times with Flask-Moment 33 4. Web Forms. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 Cross-Site Request Forgery (CSRF) Protection 37 Form Classes 38 HTML Rendering of Forms 40 Form Handling in View Functions 41 Redirects and User Sessions 44 Message Flashing 46 5. Databases. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 SQL Databases 49 NoSQL Databases 50 SQL or NoSQL? 51 Python Database Frameworks 51 Database Management with Flask-SQLAlchemy 52 Model Definition 54 Relationships 56 Database Operations 57 Creating the Tables 58 Inserting Rows 58 Modifying Rows 60 Deleting Rows 60 Querying Rows 60 Database Use in View Functions 62 Integration with the Python Shell 63 Database Migrations with Flask-Migrate 64 Creating a Migration Repository 64 Creating a Migration Script 65 Upgrading the Database 66 6. Email. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 Email Support with Flask-Mail 69 Sending Email from the Python Shell 70 Integrating Emails with the Application 71 Sending Asynchronous Email 72 7. Large Application Structure. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 Project Structure 75 Configuration Options 76 Application Package 78 vi | Table of Contents
  • 13.
    Using an ApplicationFactory 78 Implementing Application Functionality in a Blueprint 79 Launch Script 81 Requirements File 82 Unit Tests 83 Database Setup 85 Part II. Example: A Social Blogging Application 8. User Authentication. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 Authentication Extensions for Flask 89 Password Security 90 Hashing Passwords with Werkzeug 90 Creating an Authentication Blueprint 92 User Authentication with Flask-Login 94 Preparing the User Model for Logins 94 Protecting Routes 95 Adding a Login Form 96 Signing Users In 97 Signing Users Out 99 Testing Logins 99 New User Registration 100 Adding a User Registration Form 100 Registering New Users 102 Account Confirmation 103 Generating Confirmation Tokens with itsdangerous 103 Sending Confirmation Emails 105 Account Management 109 9. User Roles. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 Database Representation of Roles 111 Role Assignment 113 Role Verification 114 10. User Profiles. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119 Profile Information 119 User Profile Page 120 Profile Editor 122 User-Level Profile Editor 122 Administrator-Level Profile Editor 124 Table of Contents | vii
  • 14.
    User Avatars 127 11.Blog Posts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 Blog Post Submission and Display 131 Blog Posts on Profile Pages 134 Paginating Long Blog Post Lists 135 Creating Fake Blog Post Data 135 Rendering Data on Pages 137 Adding a Pagination Widget 138 Rich-Text Posts with Markdown and Flask-PageDown 141 Using Flask-PageDown 141 Handling Rich Text on the Server 143 Permanent Links to Blog Posts 145 Blog Post Editor 146 12. Followers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 Database Relationships Revisited 149 Many-to-Many Relationships 150 Self-Referential Relationships 151 Advanced Many-to-Many Relationships 152 Followers on the Profile Page 155 Query Followed Posts Using a Database Join 158 Show Followed Posts on the Home Page 160 13. User Comments. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 Database Representation of Comments 165 Comment Submission and Display 167 Comment Moderation 169 14. Application Programming Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 Introduction to REST 175 Resources Are Everything 176 Request Methods 177 Request and Response Bodies 177 Versioning 178 RESTful Web Services with Flask 179 Creating an API Blueprint 179 Error Handling 180 User Authentication with Flask-HTTPAuth 181 Token-Based Authentication 184 Serializing Resources to and from JSON 186 Implementing Resource Endpoints 188 viii | Table of Contents
  • 15.
    Pagination of LargeResource Collections 191 Testing Web Services with HTTPie 192 Part III. The Last Mile 15. Testing. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 Obtaining Code Coverage Reports 197 The Flask Test Client 200 Testing Web Applications 200 Testing Web Services 204 End-to-End Testing with Selenium 205 Is It Worth It? 209 16. Performance. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211 Logging Slow Database Performance 211 Source Code Profiling 213 17. Deployment. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215 Deployment Workflow 215 Logging of Errors During Production 216 Cloud Deployment 217 The Heroku Platform 218 Preparing the Application 218 Testing with Foreman 222 Enabling Secure HTTP with Flask-SSLify 223 Deploying with git push 225 Reviewing Logs 226 Deploying an Upgrade 227 Traditional Hosting 227 Server Setup 227 Importing Environment Variables 228 Setting Up Logging 228 18. Additional Resources. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231 Using an Integrated Development Environment (IDE) 231 Finding Flask Extensions 232 Getting Involved with Flask 232 Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 Table of Contents | ix
  • 17.
    Preface Flask stands outfrom other frameworks because it lets developers take the driver’s seat and have full creative control of their applications. Maybe you have heard the phrase “fighting the framework” before. This happens with most frameworks when you decide to solve a problem with a solution that isn’t the official one. It could be that you want to use a different database engine, or maybe a different method of authenticating users. Deviating from the path set by the framework’s developers will give you lots of headaches. Flask is not like that. Do you like relational databases? Great. Flask supports them all. Maybe you prefer a NoSQL database? No problem at all. Flask works with them too. Want to use your own homegrown database engine? Don’t need a database at all? Still fine. With Flask you can choose the components of your application or even write your own if that is what you want. No questions asked! ThekeytothisfreedomisthatFlaskwasdesignedfromthestarttobeextended.Itcomes with a robust core that includes the basic functionality that all web applications need and expects the rest to be provided by some of the many third-party extensions in the ecosystem and, of course, by you. In this book I present my workflow for developing web applications with Flask. I don’t claim to have the only true way to build applications with this framework. You should take my choices as recommendations and not as gospel. Most software development books provide small and focused code examples that demonstratethedifferentfeaturesofthetargettechnologyinisolation,leavingthe“glue” code that is necessary to transform these different features into a fully working appli‐ cations to be figured out by the reader. I take a completely different approach. All the examples I present are part of a single application that starts out very simple and is expanded in each successive chapter. This application begins life with just a few lines of code and ends as a nicely featured blogging and social networking application. xi
  • 18.
    Who This BookIs For You should have some level of Python coding experience to make the most of this book. Although the book assumes no previous Flask knowledge, Python concepts such as packages, modules, functions, decorators, and object-oriented programming are as‐ sumed to be well understood. Some familiarity with exceptions and diagnosing issues from stack traces will be very useful. While working through the examples in this book, you will spend a great deal of time in the command line. You should feel comfortable using the command line of your operating system. Modern web applications cannot avoid the use of HTML, CSS, and JavaScript. The example application that is developed throughout the book obviously makes use of these, but the book itself does not go into a lot of detail regarding these technologies andhowtheyareused.Somedegreeoffamiliaritywiththeselanguagesisrecommended if you intend to develop complete applications without the help of a developer versed in client-side techniques. I released the companion application to this book as open source on GitHub. Although GitHubmakesitpossibletodownloadapplicationsasregularZIPorTARfiles,Istrongly recommendthatyouinstallaGitclientandfamiliarizeyourselfwithsourcecodeversion control, at least with the basic commands to clone and check out the different versions of the application directly from the repository. The short list of commands that you’ll need is shown in “How to Work with the Example Code ” on page xiii. You will want to use version control for your own projects as well, so use this book as an excuse to learn Git! Finally, this book is not a complete and exhaustive reference on the Flask framework. Most features are covered, but you should complement this book with the official Flask documentation. How This Book Is Organized This book is divided into three parts: Part I, Introduction to Flask, explores the basics of web application development with the Flask framework and some of its extensions: • Chapter 1 describes the installation and setup of the Flask framework. • Chapter 2 dives straight into Flask with a basic application. • Chapter 3 introduces the use of templates in Flask applications. • Chapter 4 introduces web forms. • Chapter 5 introduces databases. xii | Preface
  • 19.
    • Chapter 6introduces email support. • Chapter 7 presents an application structure that is appropriate for medium and large applications. Part II, Example: A Social Blogging Application, builds Flasky, the open source blogging and social networking application that I developed for this book: • Chapter 8 implements a user authentication system. • Chapter 9 implements user roles and permissions. • Chapter 10 implements user profile pages. • Chapter 11 creates the blogging interface. • Chapter 12 implements followers. • Chapter 13 implements user comments for blog posts. • Chapter 14 implements an Application Programming Interface (API). PartIII,TheLastMile,describessomeimportanttasksnotdirectlyrelatedtoapplication coding that need to be considered before publishing an application: • Chapter 15 describes different unit testing strategies in detail. • Chapter 16 gives an overview of performance analysis techniques. • Chapter 17 describes deployment options for Flask applications, both traditional and cloud based. • Chapter 18 lists additional resources. How to Work with the Example Code The code examples presented in this book are available from GitHub at https:// github.com/miguelgrinberg/flasky. The commit history in this repository was carefully created to match the order in which concepts are presented in the book. The recommended way to work with the code is to check out the commits starting from the oldest, then move forward through the commit list as you make progress with the book. As an alternative, GitHub will also let you download each commit as a ZIP or TAR file. If you decide to use Git to work with the source code, then you need to install the Git client, which you can download from http://git-scm.com. The following command downloads the example code using Git: $ git clone https://github.com/miguelgrinberg/flasky.git Preface | xiii
  • 20.
    The git clonecommand installs the source code from GitHub into a flasky folder that is created in the current directory. This folder does not contain just source code; a copy of the Git repository with the entire history of changes made to the application is also included. In the first chapter you will be asked to check out the initial release of the application, and then, at the proper places you will be instructed to move forward in the history. The Git command that lets you move through the change history is git checkout. Here is an example: $ git checkout 1a The 1a referenced in the command is a tag, a named point in the history of the project. This repository is tagged according to the chapters of the book, so the 1a tag used in the example sets the application files to the initial version used in Chapter 1. Most chapters have more than one tag associated with them, so, for example, tags 5a, 5b, and so on are incremental versions presented in Chapter 5. In addition to checking out the source files for a version of the application, you may need to perform some setup. For example, in some cases you will need to install addi‐ tional Python packages or apply updates to the database. You will be told when these are necessary. You will normally not modify the source files of the application, but if you do, then Git will not let you check out a different revision, as that would cause your local changes to be lost. Before you can check out a different revision, you will need to revert the files to their original state. The easiest way to do this is with the git reset command: $ git reset --hard This command will destroy your local changes, so you should save anything you don’t want to lose before you use this command. From time to time, you may want to refresh your local repository from the one on GitHub, where bug fixes and improvements may have been applied. The commands that achieve this are: $ git fetch --all $ git fetch --tags $ git reset --hard origin/master The git fetch commands are used to update the commit history and the tags in your local repository from the remote one on GitHub, but none of this affects the actual source files, which are updated with the git reset command that follows. Once again, be aware that any time git reset is used you will lose any local changes you have made. Another useful operation is to view all the differences between two versions of the application.Thiscanbeveryusefultounderstandachangeindetail.Fromthecommand xiv | Preface
  • 21.
    line, the gitdiff command can do this. For example, to see the difference between revisions 2a and 2b, use: $ git diff 2a 2b The differences are shown as a patch, which is not a very intuitive format to review changes if you are not used to working with patch files. You may find that the graphical comparisons shown by GitHub are much easier to read. For example, the differences between revisions 2a and 2b can be viewed on GitHub at https://github.com/miguelgrin berg/flasky/compare/2a...2b Using Code Examples This book is here to help you get your job done. In general, if example code is offered with this book, you may use it in your programs and documentation. You do not need to contact us for permission unless you’re reproducing a significant portion of the code. For example, writing a program that uses several chunks of code from this book does not require permission. Selling or distributing a CD-ROM of examples from O’Reilly books does require permission. Answering a question by citing this book and quoting example code does not require permission. Incorporating a significant amount of ex‐ ample code from this book into your product’s documentation does require permission. We appreciate, but do not require, attribution. An attribution usually includes the title, author, publisher, and ISBN. For example: “Flask Web Development by Miguel Grinberg (O’Reilly). Copyright 2014 Miguel Grinberg, 978-1-449-3726-2.” If you feel your use of code examples falls outside fair use or the permission given above, feel free to contact us at permissions@oreilly.com. Conventions Used in This Book The following typographical conventions are used in this book: Italic Indicates new terms, URLs, email addresses, filenames, and file extensions. Constant width Used for program listings, as well as within paragraphs to refer to program elements such as variable or function names, databases, data types, environment variables, statements, and keywords. Constant width bold Shows commands or other text that should be typed literally by the user. Preface | xv
  • 22.
    Constant width italic Showstext that should be replaced with user-supplied values or by values deter‐ mined by context. This element signifies a tip or suggestion. This element signifies a general note. This element indicates a warning or caution. Safari® Books Online Safari Books Online is an on-demand digital library that delivers expert content in both book and video form from the world’s leading authors in technology and business. Technology professionals, software developers, web designers, and business and crea‐ tive professionals use Safari Books Online as their primary resource for research, prob‐ lem solving, learning, and certification training. Safari Books Online offers a range of product mixes and pricing programs for organi‐ zations, government agencies, and individuals. Subscribers have access to thousands of books, training videos, and prepublication manuscripts in one fully searchable database from publishers like O’Reilly Media, Prentice Hall Professional, Addison-Wesley Pro‐ fessional, Microsoft Press, Sams, Que, Peachpit Press, Focal Press, Cisco Press, John Wiley & Sons, Syngress, Morgan Kaufmann, IBM Redbooks, Packt, Adobe Press, FT Press, Apress, Manning, New Riders, McGraw-Hill, Jones & Bartlett, Course Technol‐ ogy, and dozens more. For more information about Safari Books Online, please visit us online. xvi | Preface
  • 23.
    How to ContactUs Please address comments and questions concerning this book to the publisher: O’Reilly Media, Inc. 1005 Gravenstein Highway North Sebastopol, CA 95472 800-998-9938 (in the United States or Canada) 707-829-0515 (international or local) 707-829-0104 (fax) We have a web page for this book, where we list errata, examples, and any additional information. You can access this page at http://www.bit.ly/flask-web-dev. To comment or ask technical questions about this book, send email to bookques tions@oreilly.com. For more information about our books, courses, conferences, and news, see our website at http://www.oreilly.com. Find us on Facebook: http://facebook.com/oreilly Follow us on Twitter: http://twitter.com/oreillymedia Watch us on YouTube: http://www.youtube.com/oreillymedia Acknowledgments I could not have written this book alone. I have received a lot of help from family, co- workers, old friends, and new friends I’ve made along the way. I’d like to thank Brendan Kohler for his detailed technical review and for his help in giving shape to the chapter on Application Programming Interfaces. I’m also in debt to David Baumgold, Todd Brunhoff, Cecil Rock, and Matthew Hugues, who reviewed the manuscript at different stages of completion and gave me very useful advice regarding what to cover and how to organize the material. Writing the code examples for this book was a considerable effort. I appreciate the help of Daniel Hofmann, who did a thorough code review of the application and pointed out several improvements. I’m also thankful to my teenage son, Dylan Grinberg, who sus‐ pended his Minecraft addiction for a few weekends and helped me test the code under several platforms. O’Reilly has a wonderful program called Early Release that allows impatient readers to have access to books while they are being written. Some of my Early Release readers went the extra mile and engaged in useful conversations regarding their experience working through the book, leading to significant improvements. I’d like to acknowledge Preface | xvii
  • 24.
    Sundeep Gupta, DanCaron, Brian Wisti and Cody Scott in particular for the contri‐ butions they’ve made to this book. The staff at O’Reilly Media has always been there for me. Above all I’d like to recognize my wonderful editor, Meghan Blanchette, for her support, advice, and assistance from the very first day we met. Meg has made the experience of writing my first book a memorable one. To conclude, I would like to give a big thank you to the awesome Flask community. xviii | Preface
  • 25.
  • 27.
    CHAPTER 1 Installation Flask isa small framework by most standards, small enough to be called a “micro- framework.” It is small enough that once you become familiar with it, you will likely be able to read and understand all of its source code. But being small does not mean that it does less than other frameworks. Flask was de‐ signed as an extensible framework from the ground up; it provides a solid core with the basic services, while extensions provide the rest. Because you can pick and choose the extension packages that you want, you end up with a lean stack that has no bloat and does exactly what you need. Flask has two main dependencies. The routing, debugging, and Web Server Gateway Interface (WSGI) subsystems come from Werkzeug, while template support is provided by Jinja2. Werkzeug and Jinja2 are authored by the core developer of Flask. There is no native support in Flask for accessing databases, validating web forms, au‐ thenticating users, or other high-level tasks. These and many other key services most web applications need are available through extensions that integrate with the core packages. As a developer, you have the power to cherry-pick the extensions that work best for your project or even write your own if you feel inclined to. This is in contrast with a larger framework, where most choices have been made for you and are hard or sometimes impossible to change. In this chapter, you will learn how to install Flask. The only requirement you need is a computer with Python installed. The code examples in this book have been verified to work with Python 2.7 and Python 3.3, so using one of these two versions is strongly recommended. 3
  • 28.
    Using Virtual Environments Themost convenient way to install Flask is to use a virtual environment. A virtual environment is a private copy of the Python interpreter onto which you can install packages privately, without affecting the global Python interpreter installed in your system. Virtual environments are very useful because they prevent package clutter and version conflicts in the system’s Python interpreter. Creating a virtual environment for each application ensures that applications have access to only the packages that they use, while the global interpreter remains neat and clean and serves only as a source from which more virtual environments can be created. As an added benefit, virtual environ‐ ments don’t require administrator rights. Virtual environments are created with the third-party virtualenv utility. To check whether you have it installed in your system, type the following command: $ virtualenv --version If you get an error, you will have to install the utility. Python 3.3 adds native support of virtual environments through the venv module and the pyvenv command. pyvenv can be used instead of virtualenv, but note that virtual environments created with py‐ venv on Python 3.3 do not include pip, which needs to be installed manually. This limitation has been removed in Python 3.4, where pyvenv can be used as a complete virtualenv replacement. Most Linux distributions provide a package for virtualenv. For example, Ubuntu users can install it with this command: $ sudo apt-get install python-virtualenv If you are using Mac OS X, then you can install virtualenv using easy_install: $ sudo easy_install virtualenv If you are using Microsoft Windows or any operating system that does not provide an official virtualenv package, then you have a slightly more complicated install procedure. Using your web browser, navigate to https://bitbucket.org/pypa/setuptools, the home of the setuptools installer. In that page, look for a link to download the installer script. This is a script called ez_setup.py. Save this file to a temporary folder on your computer, then run the following commands in that folder: $ python ez_setup.py $ easy_install virtualenv 4 | Chapter 1: Installation
  • 29.
    The previous commandsmust be issued from an account with ad‐ ministrator rights. On Microsoft Windows, start the command prompt window using the “Run as Administrator” option. On Unix- based systems, the two installation commands must be preceded with sudo or executed as the root user. Once installed, the virtualenv util‐ ity can be invoked from regular accounts. Now you need to create the folder that will host the example code, which is available from a GitHub repository. As discussed in “How to Work with the Example Code ” on page xiii, the most convenient way to do this is by checking out the code directly from GitHub using a Git client. The following commands download the example code from GitHub and initialize the application folder to version “1a,” the initial version of the application: $ git clone https://github.com/miguelgrinberg/flasky.git $ cd flasky $ git checkout 1a The next step is to create the Python virtual environment inside the flasky folder using the virtualenv command. This command has a single required argument: the name of the virtual environment. A folder with the chosen name will be created in the current directory and all files associated with the virtual environment will be inside. A com‐ monly used naming convention for virtual environments is to call them venv: $ virtualenv venv New python executable in venv/bin/python2.7 Also creating executable in venv/bin/python Installing setuptools............done. Installing pip...............done. Now you have a venv folder inside the flasky folder with a brand-new virtual environ‐ ment that contains a private Python interpreter. To start using the virtual environment, you have to “activate” it. If you are using a bash command line (Linux and Mac OS X users), you can activate the virtual environment with this command: $ source venv/bin/activate If you are using Microsoft Windows, the activation command is: $ venvScriptsactivate When a virtual environment is activated, the location of its Python interpreter is added to the PATH, but this change is not permanent; it affects only your current command session. To remind you that you have activated a virtual environment, the activation command modifies the command prompt to include the name of the environment: (venv) $ Using Virtual Environments | 5
  • 30.
    When you aredone working with the virtual environment and want to return to the global Python interpreter, type deactivate at the command prompt. Installing Python Packages with pip Most Python packages are installed with the pip utility, which virtualenv automatically addstoallvirtualenvironmentsuponcreation.Whenavirtualenvironmentisactivated, the location of the pip utility is added to the PATH. If you created the virtual environment with pyvenv under Python 3.3, then pip must be installed manually. Installation instructions are available on the pip website. Under Python 3.4, pyvenv installs pip automatically. To install Flask into the virtual environment, use the following command: (venv) $ pip install flask Withthiscommand,Flaskanditsdependenciesareinstalledinthevirtualenvironment. You can verify that Flask was installed correctly by starting the Python interpreter and trying to import it: (venv) $ python >>> import flask >>> If no errors appear, you can congratulate yourself: you are ready for the next chapter, where you will write your first web application. 6 | Chapter 1: Installation
  • 31.
    CHAPTER 2 Basic ApplicationStructure In this chapter, you will learn about the different parts of a Flask application. You will also write and run your first Flask web application. Initialization All Flask applications must create an application instance. The web server passes all requests it receives from clients to this object for handling, using a protocol called Web Server Gateway Interface (WSGI). The application instance is an object of class Flask, usually created as follows: from flask import Flask app = Flask(__name__) The only required argument to the Flask class constructor is the name of the main moduleorpackageoftheapplication.Formostapplications,Python’s__name__ variable is the correct value. The name argument that is passed to the Flask application construc‐ tor is a source of confusion among new Flask developers. Flask uses this argument to determine the root path of the application so that it later can find resource files relative to the location of the application. Later you will see more complex examples of application initialization, but for simple applications this is all that is needed. 7
  • 32.
    Routes and ViewFunctions Clients such as web browsers send requests to the web server, which in turn sends them to the Flask application instance. The application instance needs to know what code needstorunforeachURLrequested,soitkeepsamappingofURLstoPythonfunctions. The association between a URL and the function that handles it is called a route. The most convenient way to define a route in a Flask application is through the app.route decorator exposed by the application instance, which registers the decorated function as a route. The following example shows how a route is declared using this decorator: @app.route('/') def index(): return '<h1>Hello World!</h1>' Decorators are a standard feature of the Python language; they can modify the behavior of a function in different ways. A common pat‐ tern is to use decorators to register functions as handlers for an event. The previous example registers the function index() as the handler for the application’s root URL. If this application were deployed on a server associated with the www.ex‐ ample.com domain name, then navigating to http://www.example.com on your browser would trigger index() to run on the server. The return value of this function, called the response, is what the client receives. If the client is a web browser, the response is the document that is displayed to the user. Functionslikeindex() arecalledviewfunctions.Aresponsereturnedbyaviewfunction can be a simple string with HTML content, but it can also take more complex forms, as you will see later. Response strings embedded in Python code lead to code that is dif‐ ficult to maintain, and it is done here only to introduce the concept of responses. You will learn the proper way to generate responses in Chapter 3. If you pay attention to how some URLs for services that you use every day are formed, you will notice that many have variable sections. For example, the URL for your Face‐ book profile page is http://www.facebook.com/<your-name>, so your username is part of it. Flask supports these types of URLs using a special syntax in the route decorator. The following example defines a route that has a dynamic name component: 8 | Chapter 2: Basic Application Structure
  • 33.
    @app.route('/user/<name>') def user(name): return '<h1>Hello,%s!</h1>' % name The portion enclosed in angle brackets is the dynamic part, so any URLs that match the static portions will be mapped to this route. When the view function is invoked, Flask sends the dynamic component as an argument. In the earlier example view function, this argument is used to generate a personalized greeting as a response. The dynamic components in routes are strings by default but can also be defined with atype.Forexample,route/user/<int:id> wouldmatchonlyURLsthathaveaninteger in the id dynamic segment. Flask supports types int, float, and path for routes. The path type also represents a string but does not consider slashes as separators and instead considers them part of the dynamic component. Server Startup The application instance has a run method that launches Flask’s integrated development web server: if __name__ == '__main__': app.run(debug=True) The __name__ == '__main__' Python idiom is used here to ensure that the develop‐ ment web server is started only when the script is executed directly. When the script is imported by another script, it is assumed that the parent script will launch a different server, so the app.run() call is skipped. Once the server starts up, it goes into a loop that waits for requests and services them. This loop continues until the application is stopped, for example by hitting Ctrl-C. There are several option arguments that can be given to app.run() to configure the mode of operation of the web server. During development, it is convenient to enable debug mode, which among other things activates the debugger and the reloader. This is done by passing the argument debug set to True. The web server provided by Flask is not intended for production use. You will learn about production web servers in Chapter 17. A Complete Application In the previous sections, you learned about the different parts of a Flask web application, and now it is time to write one. The entire hello.py application script is nothing more Server Startup | 9
  • 34.
    than the threeparts described earlier combined in a single file. The application is shown in Example 2-1. Example 2-1. hello.py: A complete Flask application from flask import Flask app = Flask(__name__) @app.route('/') def index(): return '<h1>Hello World!</h1>' if __name__ == '__main__': app.run(debug=True) If you have cloned the application’s Git repository on GitHub, you can now run git checkout 2a to check out this version of the application. To run the application, make sure that the virtual environment you created earlier is activated and has Flask installed. Now open your web browser and type http:// 127.0.0.1:5000/ in the address bar. Figure 2-1 shows the web browser after connecting to the application. Figure 2-1. hello.py Flask application Then launch the application with the following command: 10 | Chapter 2: Basic Application Structure
  • 35.
    (venv) $ pythonhello.py * Running on http://127.0.0.1:5000/ * Restarting with reloader If you type any other URL, the application will not know how to handle it and will return an error code 404 to the browser—the familiar error that you get when you navigate to a web page that does not exist. The enhanced version of the application shown in Example 2-2 adds a second route that is dynamic. When you visit this URL, you are presented with a personalized greeting. Example 2-2. hello.py: Flask application with a dynamic route from flask import Flask app = Flask(__name__) @app.route('/') def index(): return '<h1>Hello World!</h1>' @app.route('/user/<name>') def user(name): return '<h1>Hello, %s!</h1>' % name if __name__ == '__main__': app.run(debug=True) If you have cloned the application’s Git repository on GitHub, you can now run git checkout 2b to check out this version of the application. To test the dynamic route, make sure the server is running and then navigate to http:// localhost:5000/user/Dave. The application will respond with a customized greeting, generated using the name dynamic argument. Try different names to see how the view function always generates the response based on the name given. An example is shown in Figure 2-2. A Complete Application | 11
  • 36.
    Figure 2-2. Dynamicroute The Request-Response Cycle Now that you have played with a basic Flask application, you might want to know more about how Flask works its magic. The following sections describe some of the design aspects of the framework. Application and Request Contexts When Flask receives a request from a client, it needs to make a few objects available to the view function that will handle it. A good example is the request object, which en‐ capsulates the HTTP request sent by the client. The obvious way in which Flask could give a view function access to the request object is by sending it as an argument, but that would require every single view function in the application to have an extra argument. Things get more complicated if you consider that the request object is not the only object that view functions might need to access to fulfill a request. Toavoidclutteringviewfunctionswithlotsofargumentsthatmayormaynotbeneeded, Flask uses contexts to temporarily make certain objects globally accessible. Thanks to contexts, view functions like the following one can be written: from flask import request @app.route('/') def index(): 12 | Chapter 2: Basic Application Structure
  • 37.
    user_agent = request.headers.get('User-Agent') return'<p>Your browser is %s</p>' % user_agent Note how in this view function request is used as if it was a global variable. In reality, request cannot be a global variable if you consider that in a multithreaded server the threads are working on different requests from different clients at the same time, so each thread needs to see a different object in request. Contexts enable Flask to make certain variables globally accessible to a thread without interfering with the other threads. A thread is the smallest sequence of instructions that can be man‐ aged independently. It is common for a process to have multiple ac‐ tive threads, sometimes sharing resources such as memory or file handles. Multithreaded web servers start a pool of threads and se‐ lect a thread from the pool to handle each incoming request. TherearetwocontextsinFlask:theapplicationcontextandtherequestcontext.Table2-1 shows the variables exposed by each of these contexts. Table 2-1. Flask context globals Variable name Context Description current_app Application context The application instance for the active application. g Application context An object that the application can use for temporary storage during the handling of a request. This variable is reset with each request. request Request context The request object, which encapsulates the contents of a HTTP request sent by the client. session Request context The user session, a dictionary that the application can use to store values that are “remembered” between requests. Flask activates (or pushes) the application and request contexts before dispatching a request and then removes them when the request is handled. When the application context is pushed, the current_app and g variables become available to the thread; likewise, when the request context is pushed, request and session become available as well. If any of these variables are accessed without an active application or request context, an error is generated. The four context variables will be revisited in later chap‐ ters in detail, so don’t worry if you don’t understand why they are useful yet. The following Python shell session demonstrates how the application context works: >>> from hello import app >>> from flask import current_app >>> current_app.name Traceback (most recent call last): ... RuntimeError: working outside of application context The Request-Response Cycle | 13
  • 38.
    >>> app_ctx =app.app_context() >>> app_ctx.push() >>> current_app.name 'hello' >>> app_ctx.pop() In this example, current_app.name fails when there is no application context active but becomes valid once a context is pushed. Note how an application context is obtained by invoking app.app_context() on the application instance. Request Dispatching Whentheapplicationreceivesarequestfromaclient,itneedstofindwhatviewfunction to invoke to service it. For this task, Flask looks up the URL given in the request in the application’s URL map, which contains a mapping of URLs to the view functions that handle them. Flask builds this map using the app.route decorators or the equivalent nondecorator version app.add_url_rule(). To see what the URL map in a Flask application looks like, you can inspect the map created for hello.py in the Python shell. For this test, make sure that your virtual envi‐ ronment is activated: (venv) $ python >>> from hello import app >>> app.url_map Map([<Rule '/' (HEAD, OPTIONS, GET) -> index>, <Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>, <Rule '/user/<name>' (HEAD, OPTIONS, GET) -> user>]) The / and /user/<name> routes were defined by the app.route decorators in the ap‐ plication. The /static/<filename> route is a special route added by Flask to give access to static files. You will learn more about static files in Chapter 3. The HEAD, OPTIONS, GET elements shown in the URL map are the request methods that are handled by the route. Flask attaches methods to each route so that different request methods sent to the same URL can be handled by different view functions. The HEAD and OPTIONS methods are managed automatically by Flask, so in practice it can be said that in this application the three routes in the URL map are attached to the GET method. You will learn about specifying different request methods for routes in Chapter 4. Request Hooks Sometimes it is useful to execute code before or after each request is processed. For example, at the start of each request it may be necessary to create a database connection, or authenticate the user making the request. Instead of duplicating the code that does this in every view function, Flask gives you the option to register common functions to be invoked before or after a request is dispatched to a view function. 14 | Chapter 2: Basic Application Structure
  • 39.
    Request hooks areimplemented as decorators. These are the four hooks supported by Flask: • before_first_request: Register a function to run before the first request is handled. • before_request: Register a function to run before each request. • after_request: Register a function to run after each request, if no unhandled ex‐ ceptions occurred. • teardown_request: Register a function to run after each request, even if unhandled exceptions occurred. A common pattern to share data between request hook functions and view functions is to use the g context global. For example, a before_request handler can load the logged- inuserfromthedatabaseandstoreiting.user.Later,whentheviewfunctionisinvoked, it can access the user from there. Examples of request hooks will be shown in future chapters, so don’t worry if this does not quite make sense yet. Responses When Flask invokes a view function, it expects its return value to be the response to the request. In most cases the response is a simple string that is sent back to the client as an HTML page. But the HTTP protocol requires more than a string as a response to a request. A very important part of the HTTP response is the status code, which Flask by default sets to 200, the code that indicates that the request was carried out successfully. When a view function needs to respond with a different status code, it can add the numericcodeasasecondreturnvalueaftertheresponsetext.Forexample,thefollowing view function returns a 400 status code, the code for a bad request error: @app.route('/') def index(): return '<h1>Bad Request</h1>', 400 Responses returned by view functions can also take a third argument, a dictionary of headers that are added to the HTTP response. This is rarely needed, but you will see an example in Chapter 14. Instead of returning one, two, or three values as a tuple, Flask view functions have the option of returning a Response object. The make_response() function takes one, two, or three arguments, the same values that can be returned from a view function, and returns a Response object. Sometimes it is useful to perform this conversion inside the The Request-Response Cycle | 15
  • 40.
    view function andthen use the methods of the response object to further configure the response. The following example creates a response object and then sets a cookie in it: from flask import make_response @app.route('/') def index(): response = make_response('<h1>This document carries a cookie!</h1>') response.set_cookie('answer', '42') return response There is a special type of response called a redirect. This response does not include a page document; it just gives the browser a new URL from which to load a new page. Redirects are commonly used with web forms, as you will learn in Chapter 4. A redirect is typically indicated with a 302 response status code and the URL to redirect to given in a Location header. A redirect response can be generated using a three-value return, or also with a Response object, but given its frequent use, Flask provides a redirect() helper function that creates this response: from flask import redirect @app.route('/') def index(): return redirect('http://www.example.com') Another special response is issued with the abort function, which is used for error handling. The following example returns status code 404 if the id dynamic argument given in the URL does not represent a valid user: from flask import abort @app.route('/user/<id>') def get_user(id): user = load_user(id) if not user: abort(404) return '<h1>Hello, %s</h1>' % user.name Notethatabortdoesnotreturncontrolbacktothefunctionthatcallsitbutgivescontrol back to the web server by raising an exception. Flask Extensions Flask is designed to be extended. It intentionally stays out of areas of important func‐ tionality such as database and user authentication, giving you the freedom to select the packages that fit your application the best, or to write your own if you so desire. 16 | Chapter 2: Basic Application Structure
  • 41.
    There is alarge variety of extensions for many different purposes that were created by the community, and if that is not enough, any standard Python package or library can be used as well. To give you an idea of how an extension is incorporated into an appli‐ cation, the following section adds an extension to hello.py that enhances the application with command-line arguments. Command-Line Options with Flask-Script Flask’s development web server supports a number of startup configuration options, but the only way to specify them is by passing them as arguments to the app.run() call in the script. This is not very convenient; the ideal way to pass configuration options is through command-line arguments. Flask-Script is an extension for Flask that adds a command-line parser to your Flask application. It comes packaged with a set of general-purpose options and also supports custom commands. The extension is installed with pip: (venv) $ pip install flask-script Example 2-3 shows the changes needed to add command-line parsing to the hello.py application. Example 2-3. hello.py: Using Flask-Script from flask.ext.script import Manager manager = Manager(app) # ... if __name__ == '__main__': manager.run() Extensions developed specifically for Flask are exposed under the flask.ext name‐ space. Flask-Script exports a class named Manager, which is imported from flask.ext.script. The method of initialization of this extension is common to many extensions: an in‐ stance of the main class is initialized by passing the application instance as an argument to the constructor. The created object is then used as appropriate for each extension. In this case, the server startup is routed through manager.run(), where the command line is parsed. Flask Extensions | 17
  • 42.
    If you havecloned the application’s Git repository on GitHub, you can run git checkout 2c to check out this version of the application. With these changes, the application acquires a basic set of command-line options. Run‐ ning hello.py now shows a usage message: $ python hello.py usage: hello.py [-h] {shell,runserver} ... positional arguments: {shell,runserver} shell Runs a Python shell inside Flask application context. runserver Runs the Flask development server i.e. app.run() optional arguments: -h, --help show this help message and exit The shell command is used to start a Python shell session in the context of the appli‐ cation. You can use this session to run maintenance tasks or tests, or to debug issues. The runserver command, as its name implies, starts the web server. Running python hello.py runserver startsthewebserverindebugmode,buttheremanymoreoptions available: (venv) $ python hello.py runserver --help usage: hello.py runserver [-h] [-t HOST] [-p PORT] [--threaded] [--processes PROCESSES] [--passthrough-errors] [-d] [-r] Runs the Flask development server i.e. app.run() optional arguments: -h, --help show this help message and exit -t HOST, --host HOST -p PORT, --port PORT --threaded --processes PROCESSES --passthrough-errors -d, --no-debug -r, --no-reload The --host argument is a useful option because it tells the web server what network interface to listen to for connections from clients. By default, Flask’s development web server listens for connections on localhost, so only connections originating from within the computer running the server are accepted. The following command makes the web server listen for connections on the public network interface, enabling other computers in the network to connect as well: 18 | Chapter 2: Basic Application Structure
  • 43.
    (venv) $ pythonhello.py runserver --host 0.0.0.0 * Running on http://0.0.0.0:5000/ * Restarting with reloader The web server should now be accessible from any computer in the network at http:// a.b.c.d:5000, where “a.b.c.d” is the external IP address of the computer running the server. This chapter introduced the concept of responses to requests, but there is a lot more to say about responses. Flask provides very good support for generating responses using templates, and this is such an important topic that the next chapter is dedicated to it. Flask Extensions | 19
  • 45.
    CHAPTER 3 Templates The keyto writing applications that are easy to maintain is to write clean and well- structured code. The examples that you have seen so far are too simple to demonstrate this, but Flask view functions have two completely independent purposes disguised as one, which creates a problem. The obvious task of a view function is to generate a response to a request, as you have seen in the examples shown in Chapter 2. For the simplest requests this is enough, but ingeneralarequesttriggersachangeinthestateoftheapplication,andtheviewfunction is also where this change is generated. For example, consider a user who is registering a new account on a website. The user types an email address and a password in a web form and clicks the Submit button. On the server, a request that includes the data from the user arrives and Flask dispatches it to the view function that handles registration requests. This view function needs to talk to the database to get the new user added and then generate a response to send back to the browser. These two types of tasks are formally called business logic and presentation logic, respectively. Mixing business and presentation logic leads to code that is hard to understand and maintain. Imagine having to build the HTML code for a large table by concatenating data obtained from the database with the necessary HTML string literals. Moving the presentation logic into templates helps improve the maintainability of the application. A template is a file that contains the text of a response, with placeholder variables for the dynamic parts that will be known only in the context of a request. The process that replaces the variables with actual values and returns a final response string is called rendering. For the task of rendering templates, Flask uses a powerful template engine called Jinja2. 21
  • 46.
    The Jinja2 TemplateEngine In its simplest form, a Jinja2 template is a file that contains the text of a response. Example 3-1 shows a Jinja2 template that matches the response of the index() view function of Example 2-1. Example 3-1. templates/index.html: Jinja2 template <h1>Hello World!</h1> The response returned by view function user() of Example 2-2 has a dynamic com‐ ponent, which is represented by a variable. Example 3-2 shows the template that im‐ plements this response. Example 3-2. templates/user.html: Jinja2 template <h1>Hello, {{ name }}!</h1> Rendering Templates By default Flask looks for templates in a templates subfolder located inside the applica‐ tion folder. For the next version of hello.py, you need to store the templates defined earlier in a new templates folder as index.html and user.html. The view functions in the application need to be modified to render these templates. Example 3-3 shows these changes. Example 3-3. hello.py: Rendering a template from flask import Flask, render_template # ... @app.route('/index') def index(): return render_template('index.html') @app.route('/user/<name>') def user(name): return render_template('user.html', name=name) The function render_template provided by Flask integrates the Jinja2 template engine with the application. This function takes the filename of the template as its first argu‐ ment. Any additional arguments are key/value pairs that represent actual values for variables referenced in the template. In this example, the second template is receiving a name variable. Keyword arguments like name=name in the previous example are fairly common but may seem confusing and hard to understand if you are not used to them. The “name” on the 22 | Chapter 3: Templates
  • 47.
    left side representsthe argument name, which is used in the placeholder written in the template. The “name” on the right side is a variable in the current scope that provides the value for the argument of the same name. If you have cloned the application’s Git repository on GitHub, you can run git checkout 3a to check out this version of the application. Variables The {{ name }} construct used in the template shown in Example 3-2 references a variable, a special placeholder that tells the template engine that the value that goes in that place should be obtained from data provided at the time the template is rendered. Jinja2 recognizes variables of any type, even complex types such as lists, dictionaries and objects. The following are some more examples of variables used in templates: <p>A value from a dictionary: {{ mydict['key'] }}.</p> <p>A value from a list: {{ mylist[3] }}.</p> <p>A value from a list, with a variable index: {{ mylist[myintvar] }}.</p> <p>A value from an object's method: {{ myobj.somemethod() }}.</p> Variables can be modified with filters, which are added after the variable name with a pipe character as separator. For example, the following template shows the name variable capitalized: Hello, {{ name|capitalize }} Table 3-1 lists some of the commonly used filters that come with Jinja2. Table 3-1. Jinja2 variable filters Filter name Description safe Renders the value without applying escaping capitalize Converts the first character of the value to uppercase and the rest to lowercase lower Converts the value to lowercase characters upper Converts the value to uppercase characters title Capitalizes each word in the value trim Removes leading and trailing whitespace from the value striptags Removes any HTML tags from the value before rendering The safe filter is interesting to highlight. By default Jinja2 escapes all variables for se‐ curity purposes. For example, if a variable is set to the value '<h1>Hello</h1>', Jinja2 The Jinja2 Template Engine | 23
  • 48.
    will render thestring as '&lt;h1&gt;Hello&lt;/h1&gt;', which will cause the h1 ele‐ ment to be displayed and not interpreted by the browser. Many times it is necessary to display HTML code stored in variables, and for those cases the safe filter is used. Never use the safe filter on values that aren’t trusted, such as text entered by users on web forms. The complete list of filters can be obtained from the official Jinja2 documentation. Control Structures Jinja2 offers several control structures that can be used to alter the flow of the template. This section introduces some of the most useful ones with simple examples. The following example shows how conditional statements can be entered in a template: {% if user %} Hello, {{ user }}! {% else %} Hello, Stranger! {% endif %} Another common need in templates is to render a list of elements. This example shows how this can be done with a for loop: <ul> {% for comment in comments %} <li>{{ comment }}</li> {% endfor %} </ul> Jinja2 also supports macros, which are similar to functions in Python code. For example: {% macro render_comment(comment) %} <li>{{ comment }}</li> {% endmacro %} <ul> {% for comment in comments %} {{ render_comment(comment) }} {% endfor %} </ul> To make macros more reusable, they can be stored in standalone files that are then imported from all the templates that need them: {% import 'macros.html' as macros %} <ul> 24 | Chapter 3: Templates
  • 49.
    {% for commentin comments %} {{ macros.render_comment(comment) }} {% endfor %} </ul> Portions of template code that need to be repeated in several places can be stored in a separate file and included from all the templates to avoid repetition: {% include 'common.html' %} Yet another powerful way to reuse is through template inheritance, which is similar to class inheritance in Python code. First, a base template is created with the name base.html: <html> <head> {% block head %} <title>{% block title %}{% endblock %} - My Application</title> {% endblock %} </head> <body> {% block body %} {% endblock %} </body> </html> Here the block tags define elements that a derived template can change. In this example, there are blocks called head, title, and body; note that title is contained by head. The following example is a derived template of the base template: {% extends "base.html" %} {% block title %}Index{% endblock %} {% block head %} {{ super() }} <style> </style> {% endblock %} {% block body %} <h1>Hello, World!</h1> {% endblock %} The extends directive declares that this template derives from base.html. This directive is followed by new definitions for the three blocks defined in the base template, which are inserted in the proper places. Note that the new definition of the head block, which is not empty in the base template, uses super() to retain the original contents. Real-world usage of all the control structures presented in this section will be shown later, so you will have the opportunity to see how they work. The Jinja2 Template Engine | 25
  • 50.
    Twitter Bootstrap Integrationwith Flask-Bootstrap Bootstrap is an open source framework from Twitter that provides user interface com‐ ponents to create clean and attractive web pages that are compatible with all modern web browsers. Bootstrap is a client-side framework, so the server is not directly involved with it. All the server needs to do is provide HTML responses that reference Bootstrap’s cascading style sheets (CSS) and JavaScript files and instantiate the desired components through HTML, CSS, and JavaScript code. The ideal place to do all this is in templates. The obvious way to integrate Bootstrap with the application is to make all the necessary changes to the templates. A simpler approach is to use a Flask extension called Flask- Bootstrap to simplify the integration effort. Flask-Bootstrap can be installed with pip: (venv) $ pip install flask-bootstrap Flask extensions are usually initialized at the same time the application instance is cre‐ ated. Example 3-4 shows the initialization of Flask-Bootstrap. Example 3-4. hello.py: Flask-Bootstrap initialization from flask.ext.bootstrap import Bootstrap # ... bootstrap = Bootstrap(app) Like Flask-Script in Chapter 2, Flask-Bootstrap is imported from the flask.ext name‐ space and initialized by passing the application instance in the constructor. Once Flask-Bootstrap is initialized, a base template that includes all the Bootstrap files is available to the application. This template takes advantage of Jinja2’s template inher‐ itance; the application extends a base template that has the general structure of the page including the elements that import Bootstrap. Example 3-5 shows a new version of user.html as a derived template. Example 3-5. templates/user.html: Template that uses Flask-Bootstrap {% extends "bootstrap/base.html" %} {% block title %}Flasky{% endblock %} {% block navbar %} <div class="navbar navbar-inverse" role="navigation"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> 26 | Chapter 3: Templates
  • 51.
    </button> <a class="navbar-brand" href="/">Flasky</a> </div> <divclass="navbar-collapse collapse"> <ul class="nav navbar-nav"> <li><a href="/">Home</a></li> </ul> </div> </div> </div> {% endblock %} {% block content %} <div class="container"> <div class="page-header"> <h1>Hello, {{ name }}!</h1> </div> </div> {% endblock %} The Jinja2 extends directive implements the template inheritance by referencing boot‐ strap/base.htmlfromFlask-Bootstrap.ThebasetemplatefromFlask-Bootstrapprovides a skeleton web page that includes all the Bootstrap CSS and JavaScript files. Base templates define blocks that can be overriden by derived templates. The block and endblock directives define blocks of content that are added to the base template. The user.html template above defines three blocks called title, navbar, and content. These are all blocks that the base template exports for derived templates to define. The title block is straightforward; its contents will appear between <title> tags in the header of the rendered HTML document. The navbar and content blocks are reserved for the page navigation bar and main content. In this template, the navbar block defines a simple navigation bar using Bootstrap com‐ ponents. The content block has a container <div> with a page header inside. The greet‐ ing line that was in the previous version of the template is now inside the page header. Figure 3-1 shows how the application looks with these changes. If you have cloned the application’s Git repository on GitHub, you can run git checkout 3b to check out this version of the application. The Bootstrap official documentation is a great learning resource full of copy/paste-ready examples. Twitter Bootstrap Integration with Flask-Bootstrap | 27
  • 52.
    Figure 3-1. TwitterBootstrap templates Flask-Bootstrap’s base.html template defines several other blocks that can be used in derived templates. Table 3-2 shows the complete list of available blocks. Table 3-2. Flask-Bootstrap’s base template blocks Block name Description doc The entire HTML document html_attribs Attributes inside the <html> tag html The contents of the <html> tag head The contents of the <head> tag title The contents of the <title> tag metas The list of <meta> tags styles Cascading stylesheet definitions body_attribs Attributes inside the <body> tag body The contents of the <body> tag navbar User-defined navigation bar content User-defined page content scripts JavaScript declarations at the bottom of the document Many of the blocks in Table 3-2 are used by Flask-Bootstrap itself, so overriding them directly would cause problems. For example, the styles and scripts blocks are where the Bootstrap files are declared. If the application needs to add its own content to a block thatalreadyhassomecontent,thenJinja2’ssuper()functionmustbeused.Forexample, 28 | Chapter 3: Templates
  • 53.
    this is howthe scripts block would need to be written in the derived template to add a new JavaScript file to the document: {% block scripts %} {{ super() }} <script type="text/javascript" src="my-script.js"></script> {% endblock %} Custom Error Pages When you enter an invalid route in your browser’s address bar, you get a code 404 error page. The error page is now too plain and unattractive, and it has no consistency with the page that uses Bootstrap. Flask allows an application to define custom error pages that can be based on templates, likeregularroutes.Thetwomostcommonerrorcodesare404,triggeredwhentheclient requestsapageorroutethatisnotknown,and500,triggeredwhenthereisanunhandled exception. Example 3-6 shows how to provide custom handlers for these two errors. Example 3-6. hello.py: Custom error pages @app.errorhandler(404) def page_not_found(e): return render_template('404.html'), 404 @app.errorhandler(500) def internal_server_error(e): return render_template('500.html'), 500 Error handlers return a response, like view functions. They also return the numeric status code that corresponds to the error. The templates referenced in the error handlers need to be written. These templates should follow the same layout of the regular pages, so in this case they will have a navigation bar and a page header that shows the error message. The straightforward way to write these templates is to copy templates/user.html to templates/404.html and templates/500.html and then change the page header element in these two new files to the appropriate error message, but this will generate a lot of duplication. Jinja2’s template inheritance can help with this. In the same way Flask-Bootstrap pro‐ vides a base template with the basic layout of the page, the application can define its own base template with a more complete page layout that includes the navigation bar and leaves the page content to be defined in derived templates. Example 3-7 shows templates/base.html, a new template that inherits from bootstrap/base.html and defines the navigation bar, but is itself a base template to other templates such as templates/ user.html, templates/404.html, and templates/500.html. Custom Error Pages | 29
  • 54.
    Example 3-7. templates/base.html:Base application template with navigation bar {% extends "bootstrap/base.html" %} {% block title %}Flasky{% endblock %} {% block navbar %} <div class="navbar navbar-inverse" role="navigation"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="/">Flasky</a> </div> <div class="navbar-collapse collapse"> <ul class="nav navbar-nav"> <li><a href="/">Home</a></li> </ul> </div> </div> </div> {% endblock %} {% block content %} <div class="container"> {% block page_content %}{% endblock %} </div> {% endblock %} In the content block of this template is just a container <div> element that wraps a new empty block called page_content, which derived templates can define. The templates of the application will now inherit from this template instead of directly from Flask-Bootstrap. Example 3-8 shows how simple it is to construct a custom code 404 error page that inherits from templates/base.html. Example 3-8. templates/404.html: Custom code 404 error page using template inheri‐ tance {% extends "base.html" %} {% block title %}Flasky - Page Not Found{% endblock %} {% block page_content %} <div class="page-header"> <h1>Not Found</h1> 30 | Chapter 3: Templates
  • 55.
    Exploring the Varietyof Random Documents with Different Content
  • 56.
    trenches running towardsthe enemy's position. These are connected by transversal trenches, the purpose being to get one's own position always closer to the enemy's. As soon as one's position has approached near enough to make it possible to throw hand grenades into the enemy's position the hand grenade sections have to take up their places and bombard the enemy's trenches continually with hand grenades, day and night. Some few hundred yards to the rear are the heavy modern mine throwers firing a projectile weighing 140 pounds. Those projectiles, which look like sugar loaves, fly cumbrously over to the enemy where they do great damage. The trade of war must not stop at night; so the darkness is made bright by means of illuminating rockets. The illuminating cartridge is fired from a pistol, and for a second all is bright as day. As all that kind of work was done by sappers the French hated the sappers especially, and French prisoners often told us that German prisoners with white buttons and black ribbons on their caps (sappers) would be treated without any mercy. Warned by the statements of those prisoners nearly all provided themselves with infantry uniforms. We knew that we had gradually become some specialty in the trenches. If the infantry were molested somewhere by the enemy's hand grenades they used to come running up to us and begged us to go and meet the attack. Each of us received a cigar to light the hand grenades, and then we were off. Ten or twenty of us rained hand grenades on the enemy's trench for hours until one's arm got too stiff with throwing. Thus the slaughter continued, day after day, night after night. We had 48 hours in the trenches and 12 hours' sleep. It was found impossible to divide the time differently, for we were too few. The whole of the forest had been shot and torn to tatters. The artillery was everywhere and kept the villages behind the enemy's position under fire. Once one of the many batteries which we always passed on our way from camp to the front was just firing when we came by. I interrogated one of the sighting gunners what their target might
  • 57.
    be. "Some villageor other," the gunner replied. The representative of the leader of the battery, a lieutenant-colonel, was present. One of my mates inquired whether women and children might not be in the villages. "That's neither here nor there," said the lieutenant- colonel, "the women and children are French, too, so what's the harm done? Even their litter must be annihilated so as to knock out of that nation for a hundred years any idea of war." If that "gentleman" thought to win applause he was mistaken. We went our way, leaving him to his "enjoyment." On that day an assault on the enemy's position had been ordered, and we had to be in our places at seven o'clock in the morning. The 67th regiment was to attack punctually at half past eight, the sappers taking the lead. The latter had been provided with hand grenades for that purpose. We were only some twenty yards away from the enemy. Those attacks, which were repeated every week, were prepared by artillery fire half an hour before the assault began. The artillery had to calculate their fire very carefully, because the distance between the trench and that of the enemy was very small. That distance varied from three to a hundred yards, it was nowhere more than that. At our place it was twenty yards. Punctually at eight o'clock the artillery began to thunder forth. The first three shots struck our own trench, but those following squarely hit the mark, i.e., the French trench. The artillery had got the exact range and then the volleys of whole batteries began to scream above our heads. Every time the enemy's trench or the roads leading to it were hit with wonderful accuracy. One could hear the wounded cry, a sign that many a one had already been crippled. An artillery officer made observations in the first trench and directed the fire by telephone. The artillery became silent exactly at half past eight, and we passed to the assault. But the 11th company of regiment No. 67, of which I spoke before, found itself in a such a violent machine-gun fire that eighteen men had been killed a few paces from our trench. The dead and wounded had got entangled in the wild jumble of the trees and branches encumbering the ground. Whoever could run tried to
  • 58.
    reach the enemy'strench as quickly as possible. Some of the enemy defended themselves desperately in their trench, which was filled with mud and water, and violent hand to hand fighting ensued. We stood in the water up to our knees, killing the rest of our opponents. Seriously wounded men were lying flat in the mud with only their mouths and noses showing above the water. But what did we care! They were stamped deeper in the mud, for we could not see where we were stepping; and so we rolled up the whole trench. Thereupon the conquered position was fortified as well as it could be done in all haste. Again we had won a few yards of the Argonnes at the price of many lives. That trench had changed its owners innumerable times before, a matter of course in the Argonnes, and we awaited the usual counter attack. Presently the "mules" began to get active. "Mules" are the guns of the French mountain artillery. As those guns are drawn by mules, the soldier in the Argonnes calls them "mules" for short. They are very light guns with a flat trajectory, and are fired from a distance of only 50-100 yards behind the French front. The shells of those guns whistled above our heads. Cutting their way through the branches they fly along with lightning rapidity to explode in or above some trench. In consequence of the rapid flight and the short distance the noise of the firing and the explosion almost unite in a single bang. Those "mules" are much feared by the German soldiers, because those guns are active day and night. Thus day by day we lived through the same misery.
  • 59.
    XIX CHRISTMAS IN THETRENCHES Winter had arrived and it was icy cold. The trenches, all of which had underground water, had been turned into mere mud holes. The cold at night was intense, and we had to do 48 hours' work with 12 hours' sleep. Every week we had to make an attack the result of which was in no proportion to the immense losses. During the entire four months that I was in the Argonnes we had a gain of terrain some 400 yards deep. The following fact will show the high price that was paid in human life for that little piece of France. All the regiments (some of these were the infantry regiments Nos. 145, 67, 173, and the Hirschberg sharpshooting battalion No. 5) had their own cemetery. When we were relieved in the Argonnes there were more dead in our cemetery than our regiment counted men. The 67th regiment had buried more than 2000 men in its cemetery, all of whom, with the exception of a few sappers, had belonged to regiment No. 67. Not a day passed without the loss of human lives, and on a "storming day" death had an extraordinarily rich harvest. Each day had its victims, sometimes more, sometimes fewer. It must appear quite natural that under such conditions the soldiers were not in the best of moods. The men were all completely stupefied. Just as they formerly went to work regularly to feed the wife and children they now went to the trenches in just the same regular way. That business of slaughtering and working had become an every day affair. When they conversed it was always the army leaders, the Crown Prince and Lieutenant-General von Mudra, the general in command of the 16th Army Corps, that were most criticized. The troops in the Argonnes belonged to the 16th Army Corps, to the 33rd and 34th division of infantry. Neither of the two leaders, neither the Crown Prince nor von Mudra, have I ever seen in the trenches.
  • 60.
    The staff ofthe Crown Prince had among its members the old General-Fieldmarshal Count von Haeseler, the former commander of the 16th Army Corps, a man who in times of peace was already known as a relentless slave driver. The "triplets," as we called the trio, the Crown Prince, von Mudra, and Count von Haeseler, were more hated by most of the soldiers than the Frenchman who was out with his gun to take our miserable life. Many miles behind the front the scion of the Hohenzollerns found no difficulty to spout his "knock them hard!" and, at the price of thousands of human lives, to make himself popular with the patriots at home who were sitting there behind the snug stove or at the beer table complaining that we did not advance fast enough. Von Mudra got the order "Pour le merite"; they did not think of his soldiers who had not seen a bed, nor taken off their trousers or boots for months; these were provided with food—and shells, and were almost being eaten up by vermin. That we were covered with body lice was not to be wondered at, for we had scarcely enough water for drinking purposes, and could not think of having a wash. We had worn our clothes for months without changing them; the hair on our heads and our beards had grown to great length. When we had some hours in which to rest, the lice would not let us sleep. The air in the shelters was downright pestiferous, and to that foul stench of perspiration and putrefaction was added the plague of lice. At times one was sitting up for hours and could not sleep, though one was dead tired. One could catch lice, and the more one caught the worse they got. We were urgently in want of sleep, but it was impossible to close the eyes on account of the vermin. We led a loathsome, pitiful life, and at times we said to one another that nobody at home even suspected the condition we were in. We often told one another that if later on we should relate to our families the facts as they really were they would not believe them. Many soldiers tried to put our daily experience in verse.
  • 61.
    There were manyof such jingles illustrating our barbarous handicraft. It was in the month of December and the weather was extremely cold. At times we often stood in the trenches with the mud running into our trousers' pockets. In those icy cold nights we used to sit in the trenches almost frozen to a lump of ice, and when utter exhaustion sometimes vanquished us and put us to sleep we found our boots frozen to the ground on waking up. Quite a number of soldiers suffered from frost-bitten limbs; it was mostly their toes that were frost-bitten. They had to be taken to the hospital. The soldiers on duty fired incessantly so as to keep their fingers warm. Not all the soldiers are as a rule kept ready to give battle. If no attack is expected or intended, only sentries occupy the trench. About three yards apart a man is posted behind his protective shield of steel. Nevertheless all the men are in the trench. The sentries keep their section under a continual fire, especially when it is cold and dark. The fingers get warm when one pulls the trigger. Of course, one cannot aim in the darkness, and the shots are fired at random. The sentry sweeps his section so that no hostile patrol can approach, for he is never safe in that thicket. Thus it happens that the firing is generally more violent at night than at day; but there is never an interval. The rifles are fired continually; the bullets keep whistling above our trench and patter against the branches. The mines, too, come flying over at night, dropping at a high angle. Everybody knows the scarcely audible thud, and knows at once that it is a mine without seeing anything. He warns the others by calling out, "Mine coming!" and everybody looks in the darkness for the "glow-worm," i.e., the burning fuse of the mine. The glowing fuse betrays the direction of the mine, and there are always a few short seconds left to get round some corner. The same is the case with the hand grenades. They, too, betray the line of their flight at night by their burning fuse. If they do not happen to arrive in too great numbers one mostly succeeds in getting out of their way. In daylight that is not so hard because one can overlook everything. It often
  • 62.
    happens that onecannot save oneself in time from the approaching hand grenade. In that case there is only one alternative—either to remain alive or be torn to atoms. Should a hand grenade suddenly fall before one's feet one picks it up without hesitation as swiftly as possible and throws it away, if possible back into the enemy's trench. Often, however, the fuse is of such a length that the grenade does not even explode after reaching the enemy's trench again, and the Frenchman throws it back again with fabulous celerity. In order to avoid the danger of having a grenade returned the fuse is made as short as possible, and yet a grenade will come back now and again in spite of all. To return a grenade is of course dangerous work, but a man has no great choice; if he leaves the grenade where it drops he is lost, as he cannot run away; and he knows he will be crushed to atoms, and thus his only chance is to pick up the grenade and throw it away even at the risk of having the bomb explode in his hand. I know of hand grenades thrown by the French that flew hither and thither several times. One was thrown by the French and immediately returned; it came back again in an instant, and again we threw it over to them; it did not reach the enemy's trench that time, but exploded in the air. Though in general the infantry bullets cannot do much damage while one is in the trench it happens daily that men are killed by ricochet bullets. The thousands of bullets that cut through the air every minute all pass above our heads. But some strike a tree or branch and glance off. If in that case they hit a man in the trench they cause terrible injuries, because they do not strike with their heads but lengthwise. Whenever we heard of dum-dum bullets we thought of those ricochet bullets, though we did not doubt that there were dum-dum bullets in existence. I doubt, however, if dum-dum bullets are manufactured in factories, for the following reasons:—first, because a dum-dum bullet can easily damage the barrel of a rifle and make it useless; secondly, because the average soldier would refuse to carry such ammunition, for if a man is captured and such bullets are found on him, the enemy in whose power he is would punish him by the laws of war as pitilessly as such an inhuman
  • 63.
    practice deserves tobe punished. Generally, of course, a soldier only executes his orders. However, there exist dum-dum bullets, as I mentioned before. They are manufactured by the soldiers themselves. If the point is filed or cut off a German infantry bullet, so that the nickel case is cut through and the lead core is laid bare, the bullet explodes when striking or penetrating an object. Should a man be hit in the upper arm by such a projectile the latter, by its explosive force, can mangle the arm to such an extent that it only hangs by a piece of skin. Christmas came along, and we still found ourselves at the same place without any hope of a change. We received all kinds of gifts from our relations at home and other people. We were at last able to change our underwear which we had worn for months. Christmas in the trenches! It was bitterly cold. We had procured a pine tree, for there were no fir trees to be had. We had decorated the tree with candles and cookies, and had imitated the snow with wadding. Christmas trees were burning everywhere in the trenches, and at midnight all the trees were lifted on to the parapet with their burning candles, and along the whole line German soldiers began to sing Christmas songs in chorus. "O, thou blissful, O, thou joyous, mercy bringing Christmas time!" Hundreds of men were singing the song in that fearful wood. Not a shot was fired; the French had ceased firing along the whole line. That night I was with a company that was only five paces away from the enemy. The Christmas candles were burning brightly, and were renewed again and again. For the first time we heard no shots. From everywhere, throughout the forest, one could hear powerful carols come floating over—"Peace on earth —" The French left their trenches and stood on the parapet without any fear. There they stood, quite overpowered by emotion, and all of them with cap in hand. We, too, had issued from our trenches. We
  • 64.
    exchanged gifts withthe French—chocolate, cigarettes, etc. They were all laughing, and so were we; why, we did not know. Then everybody went back to his trench, and incessantly the carol resounded, ever more solemnly, ever more longingly—"O, thou blissful—" All around silence reigned; even the murdered trees seemed to listen; the charm continued, and one scarcely dared to speak. Why could it not always be as peaceful? We thought and thought, we were as dreamers, and had forgotten everything about us.— Suddenly a shot rang out; then another one was fired somewhere. The spell was broken. All rushed to their rifles. A rolling fire. Our Christmas was over. We took up again our old existence. A young infantryman stood next to me. He tried to get out of the trench. I told him: "Stay here; the French will shoot you to pieces." "I left a box of cigars up there, and must have it back." Another one told him to wait till things quieted down somewhat. "They won't hit me; I have been here three months, and they never caught me yet." "As you wish; go ahead!" Scarcely had he put his head above the parapet when he tumbled back. Part of his brains was sticking to my belt. His cap flew high up into the air. His skull was shattered. He was dead on the spot. His trials were over. The cigars were later on fetched by another man. On the following Christmas day an army order was read out. We were forbidden to wear or have in our possession things of French origin; for, every soldier who was found in possession of such things would be put before a court-martial as a marauder by the French if they captured him. We were forbidden to use objects captured from the French, and we were especially forbidden to make use of woolen blankets, because the French were infected with scabies. Scabies is an itching skin disease, which it takes at least a week to cure. But the order had a contrary effect. If one was the owner of such an "itch-blanket" one had a chance of getting into the hospital for some days. The illness was not of a serious nature, and one was at least
  • 65.
    safe from bulletsfor a few days. Every day soldiers were sent to the hospital, and we, too, were watching for a chance to grab such a French blanket. What did a man care, if he could only get out of that hell!
  • 66.
    XX THE "ITCH"—A SAVIOR OnJanuary 5th the Germans attacked along the whole forest front, and took more than 1800 prisoners. We alone had captured 700 men of the French infantry regiment No. 120. The hand to hand fighting lasted till six o'clock at night. On that day I, together with another sapper, got into a trench section that was still being defended by eight Frenchmen. We could not back out, so we had to take up the unequal struggle. Fortunately we were well provided with hand grenades. We cut the fuses so short that they exploded at the earliest moment. I threw one in the midst of the eight Frenchmen. They had scarcely escaped the first one, when the second arrived into which they ran. We utilized their momentary confusion by throwing five more in quick succession. We had reduced our opponents to four. Then we opened a rifle fire, creeping closer and closer up to them. Their bullets kept whistling above our heads. One of the Frenchmen was shot in the mouth; three more were left. These turned to flee. In such moments one is seized with an indescribable rage and forgets all about the danger that surrounds one. We had come quite near to them, when the last one stumbled and fell forward on his face. In a trice I was on him; he fought desperately with his fists; my mate was following the other two. I kept on wrestling with my opponent. He was bleeding from his mouth; I had knocked out some of his teeth. Then he surrendered and raised his hands. I let go and then had a good look at him. He was some 35 years old, about ten years older than myself. I now felt sorry for him. He pointed to his wedding ring, talking to me all the while. I understood what he wanted—he wanted to be kept alive. He handed me his bottle, inviting me to drink wine. He cried; maybe he thought of his wife and children. I pressed his hand, and he showed me his bleeding teeth. "You are a
  • 67.
    silly fellow," Itold him; "you have been lucky. The few missing teeth don't matter. For you the slaughtering is finished; come along!" I was glad I had not killed him, and took him along myself so as to protect him from being ill-treated. When I handed him over he pressed my hand thankfully and laughed; he was happy to be safe. However bad the time he might have as prisoner he would be better off at any rate than in the trenches. At least he had a chance of getting home again. In the evening we took some of the forbidden blankets, hundreds of which we had captured that day. Ten of us were lying in a shelter, all provided with blankets. Everybody wanted to get the "itch," however strange that may sound. We undressed and rolled ourselves in those blankets. Twenty-four hours later little red pimples showed themselves all over the body, and twelve men reported sick. The blankets were used in the whole company, but all of them had not the desired effect. The doctor sent nine of us to the hospital at Montmédy, and that very evening we left the camp in high glee. The railroad depot at Apremont had been badly shelled; the next station was Chatel. Both places are a little more than three miles behind the front. At Apremont the prisoners were divided into sections. Some of the prisoners had their homes at Apremont. Their families were still occupying their houses, and the prisoners asked to be allowed to pay them a visit. I chanced to observe one of those meetings at Apremont. Two men of the landstrum led one of the prisoners to the house which he pointed out to them as his own. The young wife of the prisoner was sitting in the kitchen with her three children. We followed the men into the house. The woman became as white as a sheet when she beheld her husband suddenly. They rushed to meet each other and fell into each other's arms. We went out, for we felt that we were not wanted. The wife had not been able to get the slightest signs from her husband for the last five months, for the German forces had been between her and him. He, on the other hand, had been in the trench for months knowing that his wife and children must be there, on the other side, very near, yet not to be reached. He did not know whether they were alive or dead. He
  • 68.
    heard the Frenchshells scream above his head. Would they hit Apremont? He wondered whether it was his own house that had been set alight by a shell and was reddening the sky at night. He did not know. The uncertainty tortured him, and life became hell. Now he was at home, though only for a few hours. He had to leave again a prisoner; but now he could send a letter to his wife by the field post. He had to take leave. She had nothing she could give him—no underwear, no food, absolutely nothing. She had lost all and had to rely on the charity of the soldiers. She handed him her last money, but he returned it. We could not understand what they told each other. She took the money back; it was German money, five and ten pfennig pieces and some coppers—her whole belongings. We could no longer contain ourselves and made a collection among ourselves. We got more than ten marks together which we gave to the young woman. At first she refused to take it and looked at her husband. Then she took it and wanted to kiss our hands. We warded her off, and she ran to the nearest canteen and bought things. Returning with cigars, tobacco, matches, and sausage, she handed all over to her husband with a radiant face. She laughed, once again perhaps in a long time, and sent us grateful looks. The children clung round their father and kissed him again and again. She accompanied her husband, who carried two of the kiddies, one on each arm, while his wife carried the third child. Beaming with happiness the family marched along between the two landsturm men who had their bayonets fixed. When they had to take leave, all of them, parents and children began to weep. She knew that her husband was no longer in constant danger, and she was happy, for though she had lost much, she still had her most precious possessions. Thousands of poor men and women have met such a fate near their homes. Regular trains left Chatel. We quitted the place at 11 o'clock at night, heartily glad to leave the Argonnes behind us. We had to change trains at Vouzières, and took the train to Diedenhofen. There we saw twelve soldiers with fixed bayonets take along three Frenchmen.
  • 69.
    They were elderlymen in civilian dress. We had no idea what it signified, so we entered into a conversation with one of our fellow travelers. He was a merchant, a Frenchman living at Vouzières, and spoke German fluently. The merchant was on a business trip to Sédan, and told us that the three civilian prisoners were citizens of his town. He said: "We obtain our means of life from the German military authorities, but mostly we do not receive enough to live, and the people have nothing left of their own; all the cattle and food have been commandeered. Those three men refused to keep on working for the military authorities, because they could not live on the things they were given. They were arrested and are now being transported to Germany. Of course, we don't know what will happen to them." The man also told us that all the young men had been taken away by the Germans; all of them had been interned in Germany. At Sédan we had to wait for five hours; for hospital trains were constantly arriving. It was 2 o'clock in the afternoon of the following day when we reached Montmédy, where we went to the hospital. There all our clothes were disinfected in the "unlousing establishment," and we could take a proper bath. We were lodged in the large barracks. There one met people from all parts of the front, and all of them had only known the same misery; there was not one among them who did not curse this war. All of them were glad to be in safety, and all of them tried their best to be "sick" as long as possible. Each day we were twice treated with ointment; otherwise we were at liberty to walk about the place. One day we paid a visit to the fortress of Montmédy high up on a hill. Several hundreds of prisoners were just being fed there. They were standing about in the yard of the fortress and were eating their soup. One of the prisoners came straight up to me. I had not noticed him particularly, and recognized him only when he stood before me. He was the man I had struggled with on January 5th, and we greeted each other cordially. He had brought along a prisoner who spoke German well and who interpreted for us all we had to say to
  • 70.
    each other. Hehad seen me standing about and had recognized me at once. Again and again he told me how glad he was to be a prisoner. Like myself he was a soldier because he had to be, and not from choice. At that time we had fought with each other in blind rage; for a moment we had been deadly enemies. I felt happy at having stayed my fury at that time, and again I became aware of the utter idiocy of that barbarous slaughter. We separated with a firm handshake. A fortnight I remained at the hospital; then I had to return to the front. We had been treated well at the hospital, so we started on our return journey with mixed feelings. As soon as we arrived at Chatel, the terminus, we heard the incessant gun fire. It was no use kicking, we had to go into the forest again. When we reached our old camp, we found that different troops were occupying it. Our company had left, nobody knew for what destination. Wherever we asked, nobody could give us any information. So we had to go back to the command of our corps, the headquarters of which were at Corney at that time. We left Chatel again by a hospital train, and reached Corney after half an hour's journey. Corney harbored the General Staff of the 16th Army Corps, and we thought they surely ought to know where our company was. General von Mudra and his officers had taken up their quarters in a large villa. The house was guarded by three double sentries. We showed our pay books and hospital certificates, and an orderly led us to a spacious room. It was the telephone room. There the wires from all the divisional fronts ran together, and the apparatus were in constant use. A sergeant-major looked into the lists and upon the maps. In two minutes he had found our company. He showed us on the map where it was fighting and where its camp was. "The camp is at the northern end of Verennes," he said, "and the company belongs to the 34th division; formerly it was part of the 33rd. The position it is in is in the villages of Vauquois and Boureuilles." Then he explained to us on the map the direction we were to take, and we could trot off. We returned by rail to Chatel, and went on foot from there to Apremont. We spent the night in the half destroyed depot of Apremont. In order to get to
  • 71.
    Varennes we hadto march to the south. On our way we saw French prisoners mending the roads. Most of them were black colonial troops in picturesque uniforms. On that road Austrian motor batteries were posted. Three of those 30.5-cm. howitzers were standing behind a rocky slope, but did not fire. When at noon we reached the height of Varennes we saw the whole wide plan in front of us. Varennes itself was immediately in front of us in the valley. A little farther up on the heights was Vauquois. No houses were to be seen; one could only notice a heap of rubbish through the field glasses. Shells kept exploding in that rubbish heap continually, and we felt a cold sweat run down our backs at the thought that the place up there was our destination. We had scarcely passed the ridge when some shells exploded behind us. At that place the French were shooting with artillery at individuals. As long as Vauquois had been in their power they had been able to survey the whole country, and we comprehended why that heap of rubbish was so bitterly fought for. We ran down the slope and found ourselves in Varennes. The southern portion of the village had been shelled to pieces and gutted. Only most of the chimneys which were built apart from the bottom upward, had remained standing, thin blackened forms rising out of the ruins into the air. Everywhere we saw groups of soldiers collecting the remaining more expensive metals which were sent to Germany. Among other things church-bells melted into shapeless lumps were also loaded on wagons and taken away. All the copper, brass, tin, and lead that could be got was collected.
  • 72.
    XXI IN THE HELLOF VAUQUOIS We soon found our company, and our comrades told us what hell they had gotten into. The next morning our turn came, too. We had to reach the position before day-break, for as soon as it got light the French kept all approaches under constant fire. There was no trace of trenches at Vauquois. All that could be seen were pieces of stones. Not a stone had literally remained on the other at Vauquois. That heap of ruins, once a village, had changed hands no less than fifteen times. When we arrived half of the place was in the possession of the Germans. But the French dominated the highest point, whence they could survey the whole country for many miles around. In the absence of a trench we sought cover behind stones, for it was absolutely impossible to construct trenches; the artillery was shooting everything to pieces. Thus the soldiers squatted behind piles of stones and fired as fast as their rifles would allow. Guns of all sizes were bombarding the village incessantly. There was an army of corpses, Frenchmen and Germans, all lying about pell-mell. At first we thought that that terrible state of things was only temporary, but after a few days we recognized that a slaughter worse than madness was a continuous state of things at that place. Day and night, ever the same. With Verdun as a base of operations the French continually brought up fresh masses of troops. They had carried along a field railroad the heavy pieces of the neighboring forts of Verdun, and in the spring of 1915 an offensive of a local, but murderous kind was begun. The artillery of both sides bombarded the place to such an extent that not a foot of ground could be found that was not torn up by shells. Thousands upon thousands of shells of all sizes were employed. The bombardment from both sides lasted three days and three nights,
  • 73.
    until at lastnot a soldier, neither French nor German, was left in the village. Both sides had been obliged to retreat before the infernal fire of the opponent, for not a man would have escaped alive out of that inferno. The whole slope and height were veiled in an impenetrable smoke. In the evening of the third day the enemy's bombardment died down a little, and we were ordered to go forward again into the shell torn ruins. It was not yet quite dark when the French advanced in close order. We were in possession of almost the whole of the village, and had placed one machine-gun next to the other. We could see the projectiles of the artillery burst in great numbers among the reserves of the attackers. Our machine-guns literally mowed down the first ranks. Five times the French renewed their attack during that night, their artillery meanwhile making great gaps in our ranks. We soldiers calculated that the two sides had together some three or four thousand men killed in that one night. Next morning the French eased their attacks, and their guns treated us again to the accustomed drum fire. We stood it until 10 o'clock in the morning; then we retreated again without awaiting orders, leaving innumerable dead men behind. Again the French advanced in the face of a violent German artillery fire, and effected a lodgment at the northern edge of the village of Vauquois that used to be. A few piles of stones was all that still belonged to us. We managed to put a few stones before us as a protection. The guns of neither side could hurt us or them, for they, the enemy, were but ten paces away. But the country behind us was plowed by projectiles. In face of the machine gun fire it was found impossible to bring up ammunition. The sappers undid the coils of rope worn round their bodies, and three men or more crept back with them. One of them was killed; the others arrived safely and attached the packets of cartridges to the rope. Thus we brought up the ammunition by means of a rope running in a circle, until we had enough or till the rope was shot through. At three o'clock in the afternoon we attacked again, but found it impossible to rise from the ground on account of the hail of
  • 74.
    bullets. Everybody wasshouting, "Sappers to the front with hand grenades!" Not a sapper stirred. We are only human, after all. A sergeant-major of the infantry came creeping up. He looked as if demented, his eyes were bloodshot. "You're a sapper?" "Yes," "Advance!" "Alone?" "We're coming along!" We had to roar at each other in order to make ourselves understood in the deafening, confounded row. Another sapper lay beside me. When the sergeant- major saw that he could do nothing with me he turned to the other fellow. That man motioned to him to desist, but the sergeant-major got ever more insistent, until the sapper showed him his dagger, and then our superior slung his hook. Some twenty hand grenades were lying in front of us. Ten of them I had attached to my belt for all emergencies. I said to myself that if all of them exploded there would not be much left of me. I had a lighted cigar in my mouth. I lit one bomb after the other and threw them over to some Frenchmen who were working a machine-gun in front of me, behind a heap of stones. All around me the bullets of the machine-guns were splitting the stones. I had already thrown four grenades, but all of them had overshot the mark. I took some stones and threw them to find out how far I would have to throw in order to hit the fire spitting machine in front. My aim got more accurate each time until I hit the barrel of the gun. "If it had only been a hand grenade," I thought. An infantryman close to me was shot through the shell of one ear, half of which was cut in pieces; the blood was streaming down his neck. I had no more material for bandaging except some wadding, which I attached to his wound. In my pocket I had a roll of insulating ribbon, rubber used to insulate wires; with that I bandaged him. He pointed to the machine-gun. Thereupon I gave him my cigar, telling him to keep it well alight so as to make the fuse which I desired to light by it burn well. In quick succession I threw six hand grenades. I don't know how many of them took effect, but the rags of uniforms flying about and a demolished machine-gun said enough. When we advanced later on I observed three dead men lying round the machine-gun.
  • 75.
    That was onlyone example of the usual, daily occurrences that happen day and night, again and again and everywhere, and the immense number of such actions of individual soldiers makes the enormous loss of human life comprehensible. We were still lying there without proceeding to the attack. Again ammunition was brought up by ropes from the rear. A hand grenade duel ensued; hundreds of hand grenades were thrown by both sides. Things could not go on long like that; we felt that something was bound to happen. Without receiving an order and yet as if by command we all jumped up and advanced with the dagger in our hands right through the murderous fire, and engaged in the maddest hand to hand fighting. The daggers, sharp as razors, were plunged into head after head, chest after chest. One stood on corpses in order to make other men corpses. New enemies came running up. One had scarcely finished with one when three more appeared on the scene. We, too, got reinforcements. One continued to murder and expected to be struck down oneself the next moment. One did not care a cent for one's life, but fought like an animal. I stumbled and fell on the stones. At that very moment I caught sight of a gigantic Frenchman before me who was on the point of bringing his sapper's spade down on me. I moved aside with lightning speed, and the blow fell upon the stone. In a moment my dagger was in his stomach more than up to the hilt. He went down with a horrible cry, rolling in his blood in maddening pain. I put the bloody dagger back in my boot and took hold of the spade. All around me I beheld new enemies. The spade I found to be a handy weapon. I hit one opponent between head and shoulder. The sharp spade half went through the body; I heard the cracking of the bones that were struck. Another enemy was close to me. I dropped the spade and took hold of my dagger again. All happened as in a flash. My opponent struck me in the face, and the blood came pouring out of my mouth and nose. We began to wrestle with each other. I had the dagger in my right hand. We had taken hold of each other round the chest. He was no stronger than myself,
  • 76.
    but he heldme as firmly as I held him. We tried to fight each other with our teeth. I had the dagger in my hand, but could not strike. Who was it to be? He or I? One of us two was sure to go down. I got the dagger in such a position that its point rested on his back. Then I pressed his trembling body still more firmly to myself. He fastened his teeth in my shaggy beard, and I felt a terrible pain. I pressed him still more firmly so that his ribs almost began to crack and, summoning all my strength, I pushed the dagger into the right side of his back, just below the shoulderblade. In frightful pain he turned himself round several times, fell on his face, and lay groaning on the ground. I withdrew my dagger; he bled to death like many thousands. We had pushed back the French for some yards when we received strong assistance. After a short fight the enemy turned and fled, and we followed him as far as the southern edge of the village. There the French made a counterattack with fresh bodies of men and threw us back again for some 50 yards. Then the attack was halted, and we found ourselves again where we had been at the beginning of that four days' slaughter. Thousands of corpses were covering the ruins of Vauquois, all sacrificed in vain.
  • 77.
    XXII SENT ON FURLOUGH Forfour days and nights, without food and sleep, we had been raging like barbarians, and had spent all our strength. We were soon relieved. To our astonishment we were relieved by cavalry. They were Saxon chasseurs on horseback who were to do duty as infantrymen. It had been found impossible to make good the enormous losses of the preceding days by sending up men of the depot. So they had called upon the cavalry who, by the way, were frequently employed during that time. The soldiers who had been in a life and death struggle for four days were demoralized to such an extent that they had no longer any fighting value. We were relieved very quietly, and could then return to our camp. We did not hear before the next day that during the period described our company had suffered a total loss of 49 men. The fate of most of them was unknown; one did not know whether they were dead or prisoners or whether they lay wounded in some ambulance station. The village of Varennes was continually bombarded by French guns of large size. Several French families were still living in a part of the village that had not been so badly damaged. Every day several of the enemy's 28-cm. shells came down in that quarter. Though many inhabitants had been wounded by the shells the people could not be induced to leave their houses. Our quarters were situated near a very steep slope and were thus protected against artillery fire. They consisted of wooden shanties built by ourselves. We had brought up furniture from everywhere and had made ourselves at home; for Varennes was, after all, nearly two miles behind the front. But all the shanties were not occupied, for the number of our men diminished from day to day. At last the longed-for men from the depot arrived. Many new sapper formations
  • 78.
    had to begot together for all parts of the front, and it was therefore impossible to supply the existing sapper detachments with their regular reserves. Joyfully we greeted the new arrivals. They were, as was always the case, men of very different ages; a young boyish volunteer of 17 years would march next to an old man of the landsturm who had likewise volunteered. All of them, without any exception, have bitterly repented of their "free choice" and made no secret of it. "It's a shame," a comrade told me, "that those seventeen-year-old children should be led to the slaughter, and that their young life is being poisoned, as it needs must be in these surroundings; scarcely out of boyhood, they are being shot down like mad dogs." It took but a few days for the volunteers—all of them without an exception—to repent bitterly of their resolve, and every soldier who had been in the war for any length of time would reproach them when they gave expression to their great disappointment. "But you have come voluntarily," they were told; "we had to go, else we should have been off long ago." Yet we knew that all those young people had been under some influence and had been given a wrong picture of the war. Those soldiers who had been in the war from the start who had not been wounded, but had gone through all the fighting, were gradually all sent home on furlough for ten days. Though our company contained but 14 unwounded soldiers it was very hard to obtain the furlough. We had lost several times the number of men on our muster-roll, but all our officers were still in good physical condition. It was not until September that I managed to obtain furlough at the request of my relations, and I left for home with a resolve that at times seemed to me impossible to execute. All went well until I got to Diedenhofen. As far as that station the railroads are operated by the army authorities. At Diedenhofen they are taken over by the Imperial
  • 79.
    Railroads of Alsace-Lorraineand the Prusso-Hessian State Railroads. So I had to change, and got on a train that went to Saarbruecken. I had scarcely taken a seat in a compartment in my dirty and ragged uniform when a conductor came along to inspect the tickets. Of course, I had no ticket; I had only a furlough certificate and a pass which had been handed to me at the field railroad depot of Chatel. The conductor looked at the papers and asked me again for my ticket. I drew his attention to my pass. "That is only good for the territory of the war operations," he said; "you are now traveling on a state railroad and have to buy a ticket." I told him that I should not buy a ticket, and asked him to inform the station manager. "You," I told him, "only act according to instructions. I am not angry with you for asking of me what I shall do under no circumstances." He went off and came back with the manager. The latter also inspected my papers and told me I had to pay for the journey. "I have no means for that purpose," I told him. "For these last three years I have been in these clothes" (I pointed to my uniform), "and for three years I have therefore been without any income. Whence am I to get the money to pay for this journey?" "If you have no money for traveling you can't take furlough." I thought to myself that if they took me deep into France they were in conscience bound to take me back to where they had fetched me. Was I to be a soldier for three years and fight for the Fatherland for more than a year only to find that now they refused the free use of their railroads to a ragged soldier? I explained that I was not going to pay, that I could not save the fare from the few pfennigs' pay. I refused explicitly to pay a soldier's journey with my private money, even if—as was the case here—that soldier was myself. Finally I told him, "I must request you to inform the military railroad commander; the depot command attends to soldiers, not you." He sent me a furious look through his horn spectacles and disappeared. Two civilians were sitting in the same compartment with me; they thought it an unheard-of thing that a soldier coming from the front should be asked for his fare. Presently the depot commander came
  • 80.
    up with asergeant. He demanded to see my furlough certificate, pay books, and all my other papers. "Have you any money?" "No." "Where do you come from?" "From Chatel in the Argonnes." "How long were you at the front?" "In the fourteenth month." "Been wounded?" "No." "Have you no money at all?" "No; you don't want money at the front." "The fare must be paid. If you can't, the company must pay. Please sign this paper." I signed it without looking at it. It was all one to me what I signed, as long as they left me alone. Then the sergeant came back. "You can not travel in that compartment; you must also not converse with travelers. You have to take the first carriage marked 'Only for the military.' Get into that." "I see," I observed; "in the dogs' compartment." He turned round again and said, "Cut out those remarks." The train started, and I arrived safely home. After the first hours of meeting all at home again had passed I found myself provided with faultless underwear and had taken the urgently needed bath. Once more I could put on the civilian dress I had missed for so long a time. All of it appeared strange to me. I began to think. Under no
  • 81.
    conditions was Igoing to return to the front. But I did not know how I should succeed in getting across the frontier. I could choose between two countries only—Switzerland and Holland. It was no use going to Switzerland, for that country was surrounded by belligerent states, and it needed only a little spark to bring Switzerland into the war, and then there would be no loophole for me. There was only the nearest country left for me to choose—Holland. But how was I to get there? There was the rub. I concocted a thousand plans and discarded them again. Nobody, not even my relatives, must know about it.
  • 82.
    XXIII THE FLIGHT TOHOLLAND My furlough soon neared its end; there were only four days left. I remembered a good old friend in a Rhenish town. My plan was made. Without my family noticing it I packed a suit, boots, and all necessities, and told them at home that I was going to visit my friend. To him I revealed my intentions, and he was ready to help me in every possible manner. My furlough was over. I put on my uniform, and my relations were left in the belief that I was returning to the front. I went, however, to my friend and changed into civilian clothes. I destroyed my uniform and arms, throwing the lot into the river near by. Thus having destroyed all traces, I left and arrived at Cologne after some criss-cross traveling. Thence I journeyed to Duesseldorf and stayed at night at an hotel. I had already overstayed my leave several days. Thousands of thoughts went through my brain. I was fully aware that I would lose my life if everything did not come to pass according to the program. I intended to cross the frontier near Venlo (Holland). I knew, however, that the frontier was closely guarded. The country round Venlo, the course of the frontier in those parts were unknown to me; in fact, I was a complete stranger. I made another plan. I returned to my friend and told him that it was absolutely necessary for me to get to know the frontier district and to procure a map showing the terrain. I also informed him that I had to get hold of a false identification paper. He gave me a landsturm certificate which was to identify me in case of need. In my note- book I drew the exact course of the frontier from a railway map, and then I departed again.
  • 83.
    Dead tired, Ireached Crefeld that night by the last train. I could not go on. So I went into the first hotel and hired a room. I wrote the name that was on the false paper into the register and went to sleep. At six o'clock in the morning there was a knock at my door. "Who is there?" "The police." "The police?" "Yes; the political police." I opened the door. "Here lives ...? (he mentioned the name in which I had registered). "Yes." "Have you any identification papers?" "If you please," I said, handing him the landsturm certificate. "Everything in order; pardon me for having disturbed you." "You're welcome; you're welcome," I hastened to reply, and thought how polite the police was. That well-known leaden weight fell from my chest, but I had no mind to go to sleep again. Whilst I was dressing I heard him visit all the guests of the hotel. I had not thought of the customary inspection of strangers in frontier towns. It was a good thing I had been armed for that event. Without taking breakfast (my appetite had vanished) I went to the depot and risked traveling to Kempten in spite of the great number of policemen that were about. I calculated by the map that the frontier was still some fifteen miles away. I had not much baggage with me, only a small bag, a raincoat and an umbrella. I marched along the country road and in five hours I reached the village of
  • 84.
    Herongen. To theleft of that place was the village of Niederhofen. Everywhere I saw farmers working in the fields. They would have to inform me of how the line of the frontier ran and how it was being watched. In order to procure that information I selected only those people who, to judge by their appearance, were no "great lights of the church." Without arousing suspicion I got to know that the names of the two places were "Herongen" and "Niederhofen," and that a troop of cuirassiers were quartered at Herongen. The man told me that the soldiers were lodged in the dancing hall of the Schwarz Inn. Presently I met a man who was cutting a hedge. He was a Hollander who went home across the frontier every night; he had a passport. "You are the man for me," I thought to myself, and said aloud that I had met several Hollanders in that part of the country (he was the first one), and gave him a cigar. I mentioned to him that I had visited an acquaintance in the Schwarz Inn at Herongen. "Yes," he said; "they are there." "But my friend had to go on duty, so I am having a look round." "They have got plenty to do near the frontier." "Indeed?" "Every thirty minutes and oftener a cavalry patrol, and every quarter of an hour an infantry patrol go scouting along the frontier." "And how does the frontier run?" I queried, offering him a light for his cigar. He showed me with his hand. "Here in front of you, then right through the woods, then up there; those high steeples towering over the woods belong to the factories of Venlo."
  • 85.
    I knew enough.After a few remarks I left him. All goes according to my program, I thought. But there was a new undertaking before me. I had to venture close enough to the frontier to be able to watch the patrols without being seen by them. That I succeeded in doing during the following night. I hid in the thick underwood; open country was in front of me. I remained at that spot for three days and nights. It rained and at night it was very chilly. On the evening of the third day I resolved to execute my plan that night. Regularly every fifteen minutes a patrol of from three to six soldiers arrived. When it had got dark I changed my place for one more to the right, some five hundred yards from the frontier. I said to myself that I would have to venture out as soon as it got a little lighter. In the darkness I could not see anything. It would have to be done in twilight. I had rolled my overcoat into a bundle to avoid making a noise against the trees. I advanced just after a patrol had passed. I went forward slowly and stepped out cautiously without making a noise. Then I walked with ever increasing rapidity. Suddenly a patrol appeared on my right. The frontier was about three hundred yards away from me. The patrol had about two hundred yards to the point of the frontier nearest to me. Victory would fall to the best and swiftest runner. The patrol consisted of five men; they fired several times. That did not bother me. I threw everything away and, summoning all my strength, I made in huge leaps for the frontier which I passed like a whirlwind. I ran past the pointed frontier stone and stopped fifty yards away from it. I was quite out of breath, and an indescribable happy feeling took hold of me. I felt like crying into the world that at last I was free. I seated myself on the stump of a tree and lit a cigar, quite steadily and slowly; for now I had time. Scarcely fifty yards away, near the frontier stone, was the disappointed patrol. I read on the side of the frontier stone facing me, "Koningrjk der Nederlanden" (Kingdom of the Netherlands). I had to laugh with joy. "Who are you?" one of the German patrol called to me. "The Hollanders have now the right to
  • 86.
    Welcome to ourwebsite – the perfect destination for book lovers and knowledge seekers. We believe that every book holds a new world, offering opportunities for learning, discovery, and personal growth. That’s why we are dedicated to bringing you a diverse collection of books, ranging from classic literature and specialized publications to self-development guides and children's books. More than just a book-buying platform, we strive to be a bridge connecting you with timeless cultural and intellectual values. With an elegant, user-friendly interface and a smart search system, you can quickly find the books that best suit your interests. Additionally, our special promotions and home delivery services help you save time and fully enjoy the joy of reading. Join us on a journey of knowledge exploration, passion nurturing, and personal growth every day! ebookbell.com