Instant Download Flask Web Development Developing Web Applications With Python 1st Edition Miguel Grinberg PDF All Chapters
Instant Download Flask Web Development Developing Web Applications With Python 1st Edition Miguel Grinberg PDF All Chapters
com
https://ebookfinal.com/download/flask-web-development-
developing-web-applications-with-python-1st-edition-miguel-
grinberg/
OR CLICK BUTTON
DOWNLOAD EBOOK
https://ebookfinal.com/download/flask-web-development-1st-edition-
miguel-grinberg/
ebookfinal.com
https://ebookfinal.com/download/developing-responsive-web-
applications-with-ajax-and-jquery-1st-edition-sandeep-kumar-patel/
ebookfinal.com
https://ebookfinal.com/download/web-scraping-with-python-collecting-
data-from-the-modern-web-1st-edition-ryan-mitchell/
ebookfinal.com
https://ebookfinal.com/download/developing-web-applications-with-
visual-basic-net-and-asp-net-1st-edition-john-alexander/
ebookfinal.com
Web Engineering The Discipline of Systematic Development
of Web Applications Gerti Kappel
https://ebookfinal.com/download/web-engineering-the-discipline-of-
systematic-development-of-web-applications-gerti-kappel/
ebookfinal.com
https://ebookfinal.com/download/web-development-with-jade-1st-edition-
sean-lang/
ebookfinal.com
https://ebookfinal.com/download/enjoying-web-development-with-
tapestry-1st-edition-ka/
ebookfinal.com
https://ebookfinal.com/download/building-web-applications-with-erlang-
working-with-rest-and-web-sockets-on-yaws-1st-edition-zachary-kessin/
ebookfinal.com
https://ebookfinal.com/download/web-development-with-the-mac-1st-
edition-aaron-vegh/
ebookfinal.com
Flask Web Development
Miguel Grinberg
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
also available for most titles (http://my.safaribooksonline.com). For more information, contact our corporate/
institutional sales department: 800-998-9938 or [email protected].
Editors: Meghan Blanchette and Rachel Roumeliotis Cover Designer: Randy Comer
Production Editor: Nicole Shelby Interior Designer: David Futato
Copyeditor: Nancy Kotary Illustrator: Rebecca Demarest
Proofreader: Charles Roumeliotis
Nutshell Handbook, the Nutshell Handbook logo, and the O’Reilly logo are registered trademarks of O’Reilly
Media, Inc. Flask Web Development, the picture of a Pyrenean Mastiff, and related trade dress are trademarks
of O’Reilly Media, Inc.
Many of the designations used by manufacturers and sellers to distinguish their products are claimed as
trademarks. Where those designations appear in this book, and O’Reilly Media, Inc. was aware of a trademark
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
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
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
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!
The key to this freedom is that Flask was designed from the start to be extended. It comes
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
demonstrate the different features of the target technology in isolation, leaving the “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
and how they are used. Some degree of familiarity with these languages is recommended
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
GitHub makes it possible to download applications as regular ZIP or TAR files, I strongly
recommend that you install a Git client and familiarize yourself with source code version
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.
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:
Part III, The Last Mile, describes some important tasks not directly related to application
coding that need to be considered before publishing an application:
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. This can be very useful to understand a change in detail. From the command
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
Preface | xv
Constant width italic
Shows text that should be replaced with user-supplied values or by values deter‐
mined by context.
xvi | Preface
How to Contact Us
Please address comments and questions concerning this book to the publisher:
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
[email protected].
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
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.
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:
$ venv\Scripts\activate
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) $
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
With this command, Flask and its dependencies are installed in the virtual environment.
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
module or package of the application. For most applications, Python’s __name__ variable
is the correct value.
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
needs to run for each URL requested, so it keeps a mapping of URLs to Python functions.
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>'
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.
Functions like index() are called view functions. A response returned by a view function
can be a simple string with HTML content, but it can also take more complex forms, as
you will see later.
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:
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.
@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
@app.route('/')
def index():
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.
There are two contexts in Flask: the application context and the request context. Table 2-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
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
When the application receives a request from a client, it needs to find what view function
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.
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-
in user from the database and store it in g.user. Later, when the view function is invoked,
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
numeric code as a second return value after the response text. For example, the following
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
@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
Note that abort does not return control back to the function that calls it but gives control
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.
# ...
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 starts the web server in debug mode, but there many more options
available:
(venv) $ python hello.py runserver --help
usage: hello.py runserver [-h] [-t HOST] [-p PORT] [--threaded]
[--processes PROCESSES] [--passthrough-errors] [-d]
[-r]
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:
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
in general a request triggers a change in the state of the application, and the view function
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
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.
{% 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.html from Flask-Bootstrap. The base template from Flask-Bootstrap provides
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.
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
that already has some content, then Jinja2’s super() function must be used. For example,
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 %}
@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.
{% 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 page_content %}
<div class="page-header">
<h1>Not Found</h1>
30 | Chapter 3: Templates
Exploring the Variety of Random
Documents with Different Content
I was introduced to the Medical Director, and he showed me round, omitting
one wing, in which he told me there were a couple of cases of plague. I
happened to know that there were really about a dozen, so I readily agreed
that that part should be left out.
As prison hospital, it differed very little from others that I had seen in
England. There was the same neatness and exquisite cleanliness everywhere,
though the wards were somewhat darker, and therefore cooler, which, with
the midday sun at 106° in the shade, was not a bad thing. All the nurses
were, of course, Sisters of Mercy.[3] In fact, practically all the nursing in New
Caledonia is done by Sisters, and not a few of these heroic women had
become brides of the Black Death before I left.
Here, as in all other prison hospitals I have visited, diet, stimulants, and
medicine are absolutely at the discretion of the Director. No matter what the
cost, the spark of life must be kept alive as long as possible in the breast of
the murderer, the forger, and the thief, or the criminal whose light of reason
has already been quenched in the darkness of the Black Cell.
In fact, so careful are the authorities of their patients’ general health that
they give them nothing in the way of meat but the best beef and mutton that
can be imported from Australia; Caledonian fed meat is not considered
nourishing enough. In normal times the death-rate of Ile Nou, which is wholly
given over to convict camps, is two or three per cent. lower than that of the
town of Noumea.
Part of the Hospital Buildings, Ile Nou. The roofed-terrace in front is where the patients take
their siesta in the middle of the day. One of these is attached to each court of the Hospital.
Some of the mattresses may be seen to the right.
Then from this little flowery paradise of rest and quietness we went across
the road to another enclosure in which there were two long, white buildings, a
prison and a row of offices, at right angles to each other. This was the “bad”
side. On the other there had been invalids and invalid lunatics; here there
were only lunatics, and mostly dangerous at that—men who, after being
criminals, had become madmen; not like the dwellers in Broadmoor, who are
only criminal because they are mad.
I once paid a visit to the worst part of the men’s side at Broadmoor, but I
don’t think it was quite as bad as the long corridor which led through that
gruesome home of madness. On either hand were heavy black-painted, iron
doors, and inside these a hinged grating through which the prisoner could be
fed.
The cells were about nine feet by six feet. They had neither furniture nor
bedclothes in them. The furniture would have been smashed up either in
sheer wanton destruction or for use as missiles to hurl through the grating,
and the bedclothes would have been torn up into strips for hanging or
strangling purposes.
It has been my good or bad luck to see poor humanity in a good many
shapes and guises, but I never saw such a series of pitiful parodies of
manhood as I saw when those cell doors were opened.
Some were crouched down in the corners of their cells, muttering to
themselves and picking the sacking in which they were clothed to pieces,
thread by thread. It was no use giving them regular prison clothing, for they
would pick themselves naked in a couple of days. Others were walking up and
down the narrow limits of their cells, staring with horribly vacant eyes at the
roof or the floor, and not taking the slightest notice of us.
One man was lying down scraping with bleeding fingers at the black
asphalted floor under the impression that he was burrowing his way to
freedom; others were sitting or lying on the floor motionless as death; and
others sprang at the bars like wild beasts the moment the door was opened.
But the most horrible sight I saw during that very bad quarter of an hour
was a gaunt-faced, square-built man of middle-height who got up out of a
corner as his cell door opened, and stood in the middle facing us.
He never moved a muscle, or winked an eyelid. His eyes looked at us with
the steady, burning stare of hate and ferocity. His lips were drawn back from
his teeth like the lips of an ape in a rage, and his hands were half clenched
like claws. The man was simply the incarnation of madness, savagery, and
despair. He had gone mad in the Black Cell, and the form that his madness
had taken was the belief that nothing would nourish him but human flesh. Of
course he had to be fed by force.
When we got outside a big warder pulled up his jumper and showed me the
marks of two rows of human teeth in his side. If another man hadn’t stunned
the poor wretch with the butt of his revolver he would have bitten the piece
clean out—after which I was glad when the Doctor suggested that I should go
to his quarters and have a drink with him.
V
A CONVICT ARCADIA
Permit to visit a Prison or Penitentiary Camp en détail. This is the ordinary form; but the
Author is the only Englishman for whom the words in the left-hand corner were crossed out.
There is quite a little romance connected with this estimable family. When
Madame came out she brought her two daughters with her. Now the elder of
these had been engaged to a young man employed at the Ministry of
Colonies, and he entered the colonial service by accepting a clerkship at
Noumea. The result was naturally a meeting, and the fulfilment of the proverb
which says that an old coal is easily rekindled. The engagement broken off by
the conviction was renewed, and the wedding followed in due course. The
second daughter married a prosperous concessionnaire, and the ex-coiner,
well established, and making plenty of properly minted money, has the
satisfaction of seeing the second generation of his blood growing up in peace
and plenty about him. Imagine such a story as this being true of an English
coiner!
A little further on, on the left hand side, is a little lending library, and
cabinet de lecture. This is kept by a very grave and dignified-looking man,
clean-shaven, and keen-featured, and with the manners of a French
Chesterfield. “That man’s a lawyer,” I said to the Commandant, as we left the
library. “What is he doing here?”
“You are right. At least, he was a lawyer once, doing well, and married to a
very nice woman; but he chose to make himself a widower, and that’s why
he’s here. The old story, you know.”
Next door was a barber’s shop kept by a most gentle-handed housebreaker.
He calls himself a “capillary artist,” shaves the officials and gendarmerie, cuts
the hair of the concessionnaires, and sells perfumes and soaps to their wives
and daughters. He also is doing well.
A few doors away from him a liberé has an establishment which in a way
represents the art and literature of Bourail. He began with ten years for
forgery and embezzlement. Now he takes photographs and edits, and, I
believe, also writes the Bourail Indépendent. As a newspaper for ex-convicts
and their keepers, the title struck me as somewhat humorous.
Nearly all branches of trade were represented in that little street. But these
may be taken as fairly representative samples of the life-history of those who
run them. First, crime at home; then transportation and punishment; and then
the effort to redeem, made in perfect good faith by the Government, and, so
far as these particular camps and settlements are concerned, with distinct
success in the present.
Unhappily, however, the Government is finding out already that free and
bond colonists will not mix. They will not even live side by side, wherefore
either the whole system of concessions must be given up, or the idea of
colonising one of the richest islands in the world with French peasants,
artisans, and tradesmen must be abandoned.
Later on in the afternoon we visited the Convent, which is now simply a
girls’-school under the charge of the Sisters of St. Joseph de Cluny. A few
years ago this convent was perhaps the most extraordinary matrimonial
agency that ever existed on the face of the earth. In those days it was
officially styled, “House of Correction for Females.” The sisters had charge of
between seventy and eighty female convicts, to some of whom I shall be able
to introduce you later on in the Isle of Pines, and from among these the
bachelor or widower convict, who had obtained his provisional release and a
concession, was entitled to choose a bride to be his helpmeet on his new start
in life. The method of courtship was not exactly what we are accustomed to
consider as the fruition of love’s young or even middle-aged dream.
On our way home I was introduced to one of the most picturesque and
interesting characters that I met in the colony. We pulled up at the top of a
hill. On the right hand stood a rude cabin of mud and wattles thatched with
palm-leaves, and out of this came to greet us a strange, half-savage figure,
long-haired, long-bearded, hairy almost as a monkey on arms and legs and
breast, but still with mild and intelligent features, and rather soft brown eyes,
in which I soon found the shifting light of insanity.
Acting on a hint the Commandant had already given me, I got out and
shook hands with this ragged, shaggy creature, who looked much more like a
man who had been marooned for years on a far-away Pacific Island, than an
inhabitant of this trim, orderly Penal Settlement. I introduced myself as a
messenger from the Queen of England, who had come out for the purpose of
presenting her compliments and inquiring after his health.
This was the Pole Berezowski, who more than thirty years ago fired a
couple of shots into the carriage in which Napoleon III. and Alexander II.
were driving up the Champs Elysées. He is perfectly harmless and well-
behaved; quite contented, too, living on his little patch and in a world of
dreams, believing that every foreigner who comes to Bourail is a messenger
from some of the crowned heads of Europe, who has crossed the world to
inquire after his welfare. Through me he sent a most courteous message to
the Queen, which I did not have the honour of delivering.
That night the storm-clouds came over the mountains in good earnest, and
I was forced to abandon my intention of returning to Noumea by road, since
the said road would in a few hours be for the most part a collection of
torrents, practically impassible, to say nothing of the possibility of a cyclone.
There was nothing more to be seen or done, so I accepted the Commandant’s
offer to drive me back to the port.
On the way he told me an interesting fact and an anecdote, both of which
throw considerable light upon the convict’s opinion of the settlement of
Bourail.
The fact was this: There are in New Caledonia a class of convicts who
would be hard to find anywhere else. These are voluntary convicts, and they
are all women. A woman commits a crime in France and suffers imprisonment
for it. On her release she finds herself, as in England, a social outcast, with no
means of gaining a decent living. Instead of continuing a career of crime, as is
usually the case here, some of these women will lay their case before the
Correctional Tribunal, and petition to be transported to New Caledonia, where
they will find themselves in a society which has no right to point the finger of
scorn at them.
As a rule the petition is granted, plus a free passage, unless the woman has
friends who can pay. Generally the experiment turns out a success. The
woman gets into service or a business, or perhaps marries a liberé or
concessionnaire, and so wins her way back not only to respectability as it
goes in Caledonia, but sometimes to comfort and the possession of property
which she can leave to her children.
As a matter of fact, the proprietress of the little hotel at the port was one of
these women. She had come out with a few hundred francs that her friends
had subscribed. She now owns the hotel, which does an excellent business, a
freehold estate of thirty or forty acres, and she employs fifteen Kanakas, half
a dozen convicts, and a Chinaman—who is her husband, and works harder
than any of them.
The anecdote hinged somewhat closely on the fact, and was itself a fact.
There is a weekly market at Bourail, to which the convict farmers bring their
produce and such cows, horses, calves, etc., as they have to sell. Every two or
three years their industry is stimulated and rewarded by the holding of an
agricultural exhibition, and, as a rule, the Governor goes over to distribute the
prizes. One of these exhibitions had been held, I regret to say, a short time
before my arrival, and the Governor who has the work of colonisation very
seriously at heart, made speeches both appropriate and affecting to the
various winners as they came to receive their prizes.
At length a hoary old scoundrel, who had developed into a most successful
stock-breeder, and had become quite a man of means, came up to receive his
prizes from his Excellency’s hands. M. Feuillet, as usual, made a very nice little
speech, congratulating him on the change in his fortunes, which, by the help
of a paternal government, had transformed him from a common thief and
vagabond to an honest and prosperous owner of property.
So well did his words go home that there were tears in the eyes of the
reformed reprobate when he had finished, but there were many lips in the
audience trying hard not to smile when he replied:
“Ah, oui, mon Gouverneur! if I had only known what good chances an
unfortunate man has here I would have been here ten years before.”
What his Excellency really thought on the subject is not recorded.
The hotel was crowded that night for the steamer was to sail for Noumea,
as usual, at five o’clock in the morning; but as Madame was busy she was
kind enough to give up her own chamber to me; and so I slept comfortably to
the accompaniment of a perfect bombardment of water on the corrugated
iron roof. Others spread themselves on tables and floors as best they could,
and paid for accommodation all the same.
By four o’clock one of those magical tropic changes had occurred, and
when I turned out the moon was dropping over the hills to the westward, and
Aurora was hanging like a huge white diamond in a cloudless eastern sky. The
air was sweetly fresh and cool. There were no mosquitos, and altogether it
was a good thing to be alive, for the time being at least.
Soon after the little convict camp at the port woke up. We had our early
coffee, with a dash of something to keep the cold out, and I made an early
breakfast on tinned beef and bread—convict rations—and both very good for
a hungry man. Then came the news that the steamboat La France had tied up
at another port to the northward on account of the storm, and would not put
in an appearance until night, which made a day and another night to wait, as
the coast navigation is only possible in daylight.
I naturally said things about getting up at four o’clock for nothing more
than a day’s compulsory loafing, but I got through the day somehow with the
aid of some fishing and yarning with the surveillants and the convicts, one of
whom, a very intelligent Arab, told me, with quiet pride, the story of his
escape from New Caledonia twelve years before.
He had got to Australia in an open boat, with a pair of oars, the branch of a
tree for a mast and a shirt for a sail. He made his way to Europe, roamed the
Mediterranean as a sailor for nine years, and then, at Marseilles, he had made
friends with a man who turned out to be a mouchard. This animal, after
worming his secret out of him under pledge of eternal friendship, earned
promotion by giving him away, and so here he was for life.
He seemed perfectly content, but when I asked him what he would do with
that friend if he had him in the bush for a few minutes, I was answered by a
gleam of white teeth, a flash of black eyes, and a shake of the head, which,
taken together, were a good deal more eloquent than words.
One of the Lowest Types of Criminal Faces. An illustration of
the ease with which it is possible to disguise the chin, typical
of moral weakness, and the wild-beast mouth, which nearly
all Criminals have, by means of moustache and beard.
VII
THE PLACE OF EXILES
My next expedition was to include the forest camps to the south-west of the
island, and a visit to the Isle of Pines, an ocean paradise of which I had read
much in the days of my youth; wherefore I looked forward with some
anticipation to seeing it with the eyes of flesh. There would be no steamer for
three or four days, so the next day I took a trip over to the Peninsula of
Ducos, to the northward of the bay.
The glory of Ducos as a penal settlement is past. There are now only a few
“politicals,” and traitors, and convicts condemned a perpétuité; that is to say,
prisoners for life, with no hope of remission or release. A considerable
proportion of them are in hospital, dragging out the remainder of their
hopeless days, waiting until this or the other disease gives them final release.
The Peninsula of Ducos. In the background is Ile Nou with the Central Criminal Depôt.
VIII
A PARADISE OF KNAVES
For the next three or four days after my visit to the Peninsula of Ducos
there was nothing definite to be learnt about means of transit. In fact there
was nothing certain except the plague—always that Spectre which seemed to
stand at the end of every pathway. It was really getting quite monotonous,
and I was beginning to wonder whether I should ever get out of Noumea at
all.
Then I began making inquiries as to an over-land journey through the
interior. No, that was impossible, save at great risk and expense. The Spectre
had jumped the mountains. Huge armies of rats had appeared in the bush,
just as though some Pied Piper of Hamelin had enticed them away from the
towns into the mountains, and they were spreading the plague in all
directions among the Kanakas.
It is a curious fact that rats, who of all animals are the most susceptible to
the plague, will migrate from a plague-stricken town just as they will try to
escape from a sinking ship.
Convicts and Kanakas were dying in unknown numbers. Camps were being
closed, and the rains were coming on. There was nothing to be seen or done
worth seeing or doing, so I had to content myself with wandering about
Noumea and the neighbourhood, taking photographs, making acquaintances
with convicts and liberés and getting stories out of them, wondering the
while, as every one else was doing, what the Spectre was going to do next.
As far as I was concerned, he did me the unkindest turn that he could have
done, save one. He infected the only two decent boats on the Coast Service,
and so left me the choice between voyaging to the Isle of Pines in La France
or stopping where I was.
I had to get to the island somehow, so I chose La France, and at five
o’clock one morning, after being duly inspected and squirted, I once more
boarded the detestable little hooker.
I thought my first passage in her was bad enough, but it was nothing to
this. She was swarming with passengers, bond and free, black, white, and
yellow, from end to end. She was loaded literally down to the deck, and she
smelt, if possible, even stronger than she did before. The worst of this was
that before we got to the Isle of Pines we had to get outside the reef and into
the open water.
I have seen too much of seafaring to be easily frightened on salt water, but
I candidly admit that I was frightened then. In fact, when we got outside and
she began to feel the swell, I took out my swimming-jacket and put it on,
though, of course this was a pretty forlorn hope, as the water was swarming
with sharks and the shortest swim would have been a couple of miles. Still,
one always likes to take the last chance.
Happily, she was English-built, and high in the bows, so she took nothing
but spray over. Two or three green seas would have swamped her to a
certainty, but they didn’t come, and so in time we got there.
On board I renewed the acquaintance of the Commandant of Ile Nou, who
was taking his wife and family to the Isle of Pines, which is to Caledonia as
the Riviera is to Europe. At midday we stopped at Prony, the headquarters of
the forest camps which I was to visit later on my return; and we lunched in
the saloon with six inches of water on the floor. That was the first time I ever
saw a steamer baled out with buckets. Still, they managed to get the water
under somehow. There didn’t appear to be a pump on board.
When we passed the reef, and started on the sixty-mile run through the
open sea, some began to say their prayers and some said other things, but in
the end we worried through, and just as the evening star was growing golden
in the west we anchored in the lovely little Bay of Kuto.
Never before had I heard the anchor chain rumble through the hawse-hole
with greater thankfulness than I did then, and, judging by the limp and
bedraggled look of every one, bond and free, who went ashore, I don’t think I
was alone in hoping that I had seen the last of La France—which I hadn’t.
My friend the Commandant introduced me to his confrère of the Isle of
Pines. He was not particularly sympathetic. I believe I was the only
Englishman who had ever come to the island with authority to inspect his
domains, and he didn’t take very kindly to the idea. Still, ruler and all as he
was in his own land, the long arm of the Minister of Colonies reached even to
the Isle of Pines, and, although he did not even offer me the usual courtesy of
a glass of wine, he handed the credentials back to me, and said:
“Très bien, monsieur! If you will come and see me at nine o’clock to-
morrow morning we will make arrangements. You will, I think, find
accommodation at the canteen.”
With that I took my leave, and went out into the darkness to find the
canteen and some one to carry my luggage there. I found a surveillant, who
found a relégué, and he shouldered my bag and found the canteen, the only
semblance of an hotel on the island.
There, quite unknowingly, I stumbled upon excellent friends. The canteen-
keeper was the man whose story I told in the last chapter. I was a stranger
from a very strange land. Their resources are very limited; for
communications with the grand terre were few and far between, and yet the
twenty days that I was compelled to stop on the Isle of Pines, proved after all
to be the pleasantest time that I had spent in New Caledonia.
But there was one exception, happily only a transient experience, yet bad
enough in its way. If the plague was not on board La France it ought to have
been, for never did a fitter nursery of microbes get afloat, and when I got into
the wretched little bedroom, which was all they could fix up for me that night,
I honestly believed that the little wriggling devil had got into the white
corpuscles of my blood.
I had all the symptoms with which the conversation of the doctors at the
Cercle in Noumea had made me only too familiar—headache, stomachache,
nausea, dizziness, aching under the armpits and in the groins.
Of course, I was about as frightened as an ordinary person could very well
be, a great deal more so in fact than I had been a few years before when I
first experienced the sensation of being shot at. It may have been the fright
or the fact, but the glands were swelling.
Then I caught myself repeating fragments of “Abide with me,” mixed up
with Kipling’s “Song of the Banjo”; and when a lucid interval came I decided
that the case was serious.