forked from orbit-oss/flask
Grammatical fixes in Foreword and Tutorial
This commit is contained in:
parent
475d7076f0
commit
23fc2e56a8
12 changed files with 98 additions and 96 deletions
|
|
@ -4,8 +4,8 @@ Step 7: Adding Style
|
|||
====================
|
||||
|
||||
Now that everything else works, it's time to add some style to the
|
||||
application. Just create a stylesheet called :file:`style.css` in the :file:`static`
|
||||
folder we created before:
|
||||
application. Just create a stylesheet called :file:`style.css` in the
|
||||
:file:`static` folder we created before:
|
||||
|
||||
.. sourcecode:: css
|
||||
|
||||
|
|
|
|||
|
|
@ -4,29 +4,29 @@ Step 3: Database Connections
|
|||
----------------------------
|
||||
|
||||
We have created a function for establishing a database connection with
|
||||
`connect_db` but by itself that's not particularly useful. Creating and
|
||||
`connect_db`, but by itself, that's not particularly useful. Creating and
|
||||
closing database connections all the time is very inefficient, so we want
|
||||
to keep it around for longer. Because database connections encapsulate a
|
||||
transaction we also need to make sure that only one request at the time
|
||||
uses the connection. So how can we elegantly do that with Flask?
|
||||
transaction, we also need to make sure that only one request at the time
|
||||
uses the connection. How can we elegantly do that with Flask?
|
||||
|
||||
This is where the application context comes into play. So let's start
|
||||
This is where the application context comes into play, so let's start
|
||||
there.
|
||||
|
||||
Flask provides us with two contexts: the application context and the
|
||||
request context. For the time being all you have to know is that there
|
||||
are special variables that use these. For instance the
|
||||
request context. For the time being, all you have to know is that there
|
||||
are special variables that use these. For instance, the
|
||||
:data:`~flask.request` variable is the request object associated with
|
||||
the current request, whereas :data:`~flask.g` is a general purpose
|
||||
variable associated with the current application context. We will go into
|
||||
the details of this a bit later.
|
||||
|
||||
For the time being all you have to know is that you can store information
|
||||
For the time being, all you have to know is that you can store information
|
||||
safely on the :data:`~flask.g` object.
|
||||
|
||||
So when do you put it on there? To do that you can make a helper
|
||||
function. The first time the function is called it will create a database
|
||||
connection for the current context and successive calls will return the
|
||||
function. The first time the function is called, it will create a database
|
||||
connection for the current context, and successive calls will return the
|
||||
already established connection::
|
||||
|
||||
def get_db():
|
||||
|
|
@ -39,7 +39,7 @@ already established connection::
|
|||
|
||||
|
||||
So now we know how to connect, but how do we properly disconnect? For
|
||||
that flask provides us with the :meth:`~flask.Flask.teardown_appcontext`
|
||||
that, Flask provides us with the :meth:`~flask.Flask.teardown_appcontext`
|
||||
decorator. It's executed every time the application context tears down::
|
||||
|
||||
@app.teardown_appcontext
|
||||
|
|
@ -49,11 +49,11 @@ decorator. It's executed every time the application context tears down::
|
|||
g.sqlite_db.close()
|
||||
|
||||
Functions marked with :meth:`~flask.Flask.teardown_appcontext` are called
|
||||
every time the app context tears down. So what does this mean?
|
||||
Essentially the app context is created before the request comes in and is
|
||||
every time the app context tears down. What does this mean?
|
||||
Essentially, the app context is created before the request comes in and is
|
||||
destroyed (torn down) whenever the request finishes. A teardown can
|
||||
happen because of two reasons: either everything went well (the error
|
||||
parameter will be ``None``) or an exception happened in which case the error
|
||||
parameter will be ``None``) or an exception happened, in which case the error
|
||||
is passed to the teardown function.
|
||||
|
||||
Curious about what these contexts mean? Have a look at the
|
||||
|
|
|
|||
|
|
@ -5,24 +5,24 @@ Step 4: Creating The Database
|
|||
|
||||
As outlined earlier, Flaskr is a database powered application, and more
|
||||
precisely, it is an application powered by a relational database system. Such
|
||||
systems need a schema that tells them how to store that information. So
|
||||
before starting the server for the first time it's important to create
|
||||
systems need a schema that tells them how to store that information.
|
||||
Before starting the server for the first time, it's important to create
|
||||
that schema.
|
||||
|
||||
Such a schema can be created by piping the `schema.sql` file into the
|
||||
Such a schema can be created by piping the ``schema.sql`` file into the
|
||||
`sqlite3` command as follows::
|
||||
|
||||
sqlite3 /tmp/flaskr.db < schema.sql
|
||||
|
||||
The downside of this is that it requires the sqlite3 command to be
|
||||
installed which is not necessarily the case on every system. This also
|
||||
requires that we provide the path to the database which can introduce
|
||||
The downside of this is that it requires the ``sqlite3`` command to be
|
||||
installed, which is not necessarily the case on every system. This also
|
||||
requires that we provide the path to the database, which can introduce
|
||||
errors. It's a good idea to add a function that initializes the database
|
||||
for you to the application.
|
||||
|
||||
To do this we can create a function and hook it into the :command:`flask` command
|
||||
that initializes the database. Let me show you the code first. Just add
|
||||
this function below the `connect_db` function in :file:`flaskr.py`::
|
||||
To do this, we can create a function and hook it into the :command:`flask`
|
||||
command that initializes the database. Let me show you the code first. Just
|
||||
add this function below the `connect_db` function in :file:`flaskr.py`::
|
||||
|
||||
def init_db():
|
||||
db = get_db()
|
||||
|
|
@ -37,36 +37,36 @@ this function below the `connect_db` function in :file:`flaskr.py`::
|
|||
print 'Initialized the database.'
|
||||
|
||||
The ``app.cli.command()`` decorator registers a new command with the
|
||||
:command:`flask` script. When the command executes Flask will automatically
|
||||
:command:`flask` script. When the command executes, Flask will automatically
|
||||
create a application context for us bound to the right application.
|
||||
Within the function we can then access :attr:`flask.g` and other things as
|
||||
Within the function, we can then access :attr:`flask.g` and other things as
|
||||
we would expect. When the script ends, the application context tears down
|
||||
and the database connection is released.
|
||||
|
||||
We want to keep an actual functions around that initializes the database
|
||||
though so that we can easily create databases in unittests later. (For
|
||||
We want to keep an actual functions around that initializes the database,
|
||||
though, so that we can easily create databases in unit tests later on. (For
|
||||
more information see :ref:`testing`.)
|
||||
|
||||
The :func:`~flask.Flask.open_resource` method of the application object
|
||||
is a convenient helper function that will open a resource that the
|
||||
application provides. This function opens a file from the resource
|
||||
location (your `flaskr` folder) and allows you to read from it. We are
|
||||
location (your ``flaskr`` folder) and allows you to read from it. We are
|
||||
using this here to execute a script on the database connection.
|
||||
|
||||
The connection object provided by SQLite can give us a cursor object.
|
||||
On that cursor there is a method to execute a complete script. Finally we
|
||||
only have to commit the changes. SQLite 3 and other transactional
|
||||
On that cursor, there is a method to execute a complete script. Finally, we
|
||||
only have to commit the changes. SQLite3 and other transactional
|
||||
databases will not commit unless you explicitly tell it to.
|
||||
|
||||
Now it is possible to create a database with the :command:`flask` script::
|
||||
Now, it is possible to create a database with the :command:`flask` script::
|
||||
|
||||
flask --app=flaskr initdb
|
||||
Initialized the database.
|
||||
|
||||
.. admonition:: Troubleshooting
|
||||
|
||||
If you get an exception later that a table cannot be found check that
|
||||
you did execute the `initdb` command and that your table names are
|
||||
correct (singular vs. plural for example).
|
||||
If you get an exception later on stating that a table cannot be found, check
|
||||
that you did execute the ``initdb`` command and that your table names are
|
||||
correct (singular vs. plural, for example).
|
||||
|
||||
Continue with :ref:`tutorial-views`
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@ application::
|
|||
/static
|
||||
/templates
|
||||
|
||||
The `flaskr` folder is not a python package, but just something where we
|
||||
drop our files. We will then put our database schema as well as main module
|
||||
into this folder. It is done in the following way. The files inside
|
||||
The ``flaskr`` folder is not a Python package, but just something where we
|
||||
drop our files. Later on, we will put our database schema as well as main
|
||||
module into this folder. It is done in the following way. The files inside
|
||||
the :file:`static` folder are available to users of the application via HTTP.
|
||||
This is the place where css and javascript files go. Inside the
|
||||
:file:`templates` folder Flask will look for `Jinja2`_ templates. The
|
||||
templates you create later in the tutorial will go in this directory.
|
||||
This is the place where CSS and Javascript files go. Inside the
|
||||
:file:`templates` folder, Flask will look for `Jinja2`_ templates. The
|
||||
templates you create later on in the tutorial will go in this directory.
|
||||
|
||||
Continue with :ref:`tutorial-schema`.
|
||||
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ Tutorial
|
|||
========
|
||||
|
||||
You want to develop an application with Python and Flask? Here you have
|
||||
the chance to learn that by example. In this tutorial we will create a
|
||||
simple microblog application. It only supports one user that can create
|
||||
the chance to learn by example. In this tutorial, we will create a simple
|
||||
microblogging application. It only supports one user that can create
|
||||
text-only entries and there are no feeds or comments, but it still
|
||||
features everything you need to get started. We will use Flask and SQLite
|
||||
as database which comes out of the box with Python, so there is nothing
|
||||
as a database (which comes out of the box with Python) so there is nothing
|
||||
else you need.
|
||||
|
||||
If you want the full source code in advance or for comparison, check out
|
||||
|
|
|
|||
|
|
@ -3,25 +3,25 @@
|
|||
Introducing Flaskr
|
||||
==================
|
||||
|
||||
We will call our blogging application flaskr here, feel free to choose a
|
||||
less web-2.0-ish name ;) Basically we want it to do the following things:
|
||||
We will call our blogging application flaskr, but feel free to choose your own
|
||||
less Web-2.0-ish name ;) Essentially, we want it to do the following things:
|
||||
|
||||
1. let the user sign in and out with credentials specified in the
|
||||
1. Let the user sign in and out with credentials specified in the
|
||||
configuration. Only one user is supported.
|
||||
2. when the user is logged in they can add new entries to the page
|
||||
2. When the user is logged in, they can add new entries to the page
|
||||
consisting of a text-only title and some HTML for the text. This HTML
|
||||
is not sanitized because we trust the user here.
|
||||
3. the page shows all entries so far in reverse order (newest on top) and
|
||||
the user can add new ones from there if logged in.
|
||||
3. The index page shows all entries so far in reverse chronological order
|
||||
(newest on top) and the user can add new ones from there if logged in.
|
||||
|
||||
We will be using SQLite3 directly for that application because it's good
|
||||
enough for an application of that size. For larger applications however
|
||||
it makes a lot of sense to use `SQLAlchemy`_ that handles database
|
||||
connections in a more intelligent way, allows you to target different
|
||||
We will be using SQLite3 directly for this application because it's good
|
||||
enough for an application of this size. For larger applications, however,
|
||||
it makes a lot of sense to use `SQLAlchemy`_, as it handles database
|
||||
connections in a more intelligent way, allowing you to target different
|
||||
relational databases at once and more. You might also want to consider
|
||||
one of the popular NoSQL databases if your data is more suited for those.
|
||||
|
||||
Here a screenshot from the final application:
|
||||
Here a screenshot of the final application:
|
||||
|
||||
.. image:: ../_static/flaskr.png
|
||||
:align: center
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
Step 1: Database Schema
|
||||
=======================
|
||||
|
||||
First we want to create the database schema. Only a single table is needed
|
||||
for this application and we only want to support SQLite so creating the
|
||||
First, we want to create the database schema. Only a single table is needed
|
||||
for this application and we only want to support SQLite, so creating the
|
||||
database schema is quite easy. Just put the following contents into a file
|
||||
named `schema.sql` in the just created `flaskr` folder:
|
||||
|
||||
|
|
@ -17,8 +17,8 @@ named `schema.sql` in the just created `flaskr` folder:
|
|||
'text' text not null
|
||||
);
|
||||
|
||||
This schema consists of a single table called `entries` and each row in
|
||||
this table has an `id`, a `title` and a `text`. The `id` is an
|
||||
This schema consists of a single table called ``entries``. Each row in
|
||||
this table has an ``id``, a ``title``, and a ``text``. The ``id`` is an
|
||||
automatically incrementing integer and a primary key, the other two are
|
||||
strings that must not be null.
|
||||
|
||||
|
|
|
|||
|
|
@ -3,15 +3,15 @@
|
|||
Step 2: Application Setup Code
|
||||
==============================
|
||||
|
||||
Now that we have the schema in place we can create the application module.
|
||||
Let's call it flaskr.py. We will place this file inside the flaskr folder.
|
||||
We will begin by adding the imports we need and by adding the config
|
||||
Now that we have the schema in place, we can create the application module.
|
||||
Let's call it ``flaskr.py``. We will place this file inside the ``flaskr``
|
||||
folder. We will begin by adding the imports we need and by adding the config
|
||||
section. For small applications, it is possible to drop the configuration
|
||||
directly into the module, and this is what we will be doing here. However
|
||||
a cleaner solution would be to create a separate ``.ini`` or ``.py`` file and
|
||||
load that or import the values from there.
|
||||
directly into the module, and this is what we will be doing here. However,
|
||||
a cleaner solution would be to create a separate ``.ini`` or ``.py`` file,
|
||||
load that, and import the values from there.
|
||||
|
||||
First we add the imports in :file:`flaskr.py`::
|
||||
First, we add the imports in :file:`flaskr.py`::
|
||||
|
||||
# all the imports
|
||||
import os
|
||||
|
|
@ -19,8 +19,8 @@ First we add the imports in :file:`flaskr.py`::
|
|||
from flask import Flask, request, session, g, redirect, url_for, abort, \
|
||||
render_template, flash
|
||||
|
||||
Next we can create our actual application and initialize it with the
|
||||
config from the same file, in :file:`flaskr.py`::
|
||||
Next, we can create our actual application and initialize it with the
|
||||
config from the same file in :file:`flaskr.py`::
|
||||
|
||||
# create our little application :)
|
||||
app = Flask(__name__)
|
||||
|
|
@ -35,45 +35,47 @@ config from the same file, in :file:`flaskr.py`::
|
|||
))
|
||||
app.config.from_envvar('FLASKR_SETTINGS', silent=True)
|
||||
|
||||
The :class:`~flask.Config` object works similar to a dictionary so we
|
||||
The :class:`~flask.Config` object works similarly to a dictionary so we
|
||||
can update it with new values.
|
||||
|
||||
.. admonition:: Database Path
|
||||
|
||||
Operating systems know the concept of a current working directory for
|
||||
each process. Unfortunately you cannot depend on this in web
|
||||
each process. Unfortunately, you cannot depend on this in web
|
||||
applications because you might have more than one application in the
|
||||
same process.
|
||||
|
||||
For this reason the ``app.root_path`` attribute can be used to
|
||||
get the path to the application. Together with the ``os.path`` module
|
||||
files can then easily be found. In this example we place the
|
||||
get the path to the application. Together with the ``os.path`` module,
|
||||
files can then easily be found. In this example, we place the
|
||||
database right next to it.
|
||||
|
||||
For a real-work application it's recommended to use
|
||||
For a real-world application, it's recommended to use
|
||||
:ref:`instance-folders` instead.
|
||||
|
||||
Usually, it is a good idea to load a separate, environment specific
|
||||
Usually, it is a good idea to load a separate, environment-specific
|
||||
configuration file. Flask allows you to import multiple configurations and it
|
||||
will use the setting defined in the last import. This enables robust
|
||||
configuration setups. :meth:`~flask.Config.from_envvar` can help achieve this.
|
||||
|
||||
app.config.from_envvar('FLASKR_SETTINGS', silent=True)
|
||||
.. code-block:: python
|
||||
|
||||
app.config.from_envvar('FLASKR_SETTINGS', silent=True)
|
||||
|
||||
Simply define the environment variable :envvar:`FLASKR_SETTINGS` that points to
|
||||
a config file to be loaded. The silent switch just tells Flask to not complain
|
||||
if no such environment key is set.
|
||||
|
||||
In addition to that you can use the :meth:`~flask.Config.from_object`
|
||||
In addition to that, you can use the :meth:`~flask.Config.from_object`
|
||||
method on the config object and provide it with an import name of a
|
||||
module. Flask will then initialize the variable from that module. Note
|
||||
that in all cases only variable names that are uppercase are considered.
|
||||
that in all cases, only variable names that are uppercase are considered.
|
||||
|
||||
The ``SECRET_KEY`` is needed to keep the client-side sessions secure.
|
||||
Choose that key wisely and as hard to guess and complex as possible.
|
||||
|
||||
We will also add a method that allows for easily connecting to the
|
||||
specified database. This can be used to open a connection on request and
|
||||
We will also add a method that allows for easy connections to the
|
||||
specified database. This can be used to open a connection on request and
|
||||
also from the interactive Python shell or a script. This will come in
|
||||
handy later. We create a simple database connection through SQLite and
|
||||
then tell it to use the :class:`sqlite3.Row` object to represent rows.
|
||||
|
|
@ -88,7 +90,7 @@ tuples.
|
|||
rv.row_factory = sqlite3.Row
|
||||
return rv
|
||||
|
||||
With that out of the way you should be able to start up the application
|
||||
With that out of the way, you should be able to start up the application
|
||||
without problems. Do this with the following command::
|
||||
|
||||
flask --app=flaskr --debug run
|
||||
|
|
@ -100,9 +102,9 @@ users to execute code on the server!
|
|||
You will see a message telling you that server has started along with
|
||||
the address at which you can access it.
|
||||
|
||||
When you head over to the server in your browser you will get an 404
|
||||
page not found error because we don't have any views yet. But we will
|
||||
focus on that a little later. First we should get the database working.
|
||||
When you head over to the server in your browser, you will get a 404 error
|
||||
because we don't have any views yet. We will focus on that a little later,
|
||||
but first, we should get the database working.
|
||||
|
||||
.. admonition:: Externally Visible Server
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
Step 6: The Templates
|
||||
=====================
|
||||
|
||||
Now we should start working on the templates. If we request the URLs now
|
||||
we would only get an exception that Flask cannot find the templates. The
|
||||
Now we should start working on the templates. If we were torequest the URLs
|
||||
now, we would only get an exception that Flask cannot find the templates. The
|
||||
templates are using `Jinja2`_ syntax and have autoescaping enabled by
|
||||
default. This means that unless you mark a value in the code with
|
||||
:class:`~flask.Markup` or with the ``|safe`` filter in the template,
|
||||
|
|
@ -88,7 +88,7 @@ method:
|
|||
login.html
|
||||
----------
|
||||
|
||||
Finally the login template which basically just displays a form to allow
|
||||
This is the login template, which basically just displays a form to allow
|
||||
the user to login:
|
||||
|
||||
.. sourcecode:: html+jinja
|
||||
|
|
|
|||
|
|
@ -6,5 +6,5 @@ Bonus: Testing the Application
|
|||
Now that you have finished the application and everything works as
|
||||
expected, it's probably not a bad idea to add automated tests to simplify
|
||||
modifications in the future. The application above is used as a basic
|
||||
example of how to perform unittesting in the :ref:`testing` section of the
|
||||
example of how to perform unit testing in the :ref:`testing` section of the
|
||||
documentation. Go there to see how easy it is to test Flask applications.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Step 5: The View Functions
|
||||
==========================
|
||||
|
||||
Now that the database connections are working we can start writing the
|
||||
Now that the database connections are working, we can start writing the
|
||||
view functions. We will need four of them:
|
||||
|
||||
Show Entries
|
||||
|
|
@ -15,7 +15,7 @@ The one with the highest id (the newest entry) will be on top. The rows
|
|||
returned from the cursor look a bit like tuples because we are using
|
||||
the :class:`sqlite3.Row` row factory.
|
||||
|
||||
The view function will pass the entries as dicts to the
|
||||
The view function will pass the entries as dictionaries to the
|
||||
:file:`show_entries.html` template and return the rendered one::
|
||||
|
||||
@app.route('/')
|
||||
|
|
@ -29,8 +29,8 @@ Add New Entry
|
|||
-------------
|
||||
|
||||
This view lets the user add new entries if they are logged in. This only
|
||||
responds to ``POST`` requests, the actual form is shown on the
|
||||
`show_entries` page. If everything worked out well we will
|
||||
responds to ``POST`` requests; the actual form is shown on the
|
||||
`show_entries` page. If everything worked out well, we will
|
||||
:func:`~flask.flash` an information message to the next request and
|
||||
redirect back to the `show_entries` page::
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ Login and Logout
|
|||
|
||||
These functions are used to sign the user in and out. Login checks the
|
||||
username and password against the ones from the configuration and sets the
|
||||
`logged_in` key in the session. If the user logged in successfully, that
|
||||
`logged_in` key for the session. If the user logged in successfully, that
|
||||
key is set to ``True``, and the user is redirected back to the `show_entries`
|
||||
page. In addition, a message is flashed that informs the user that he or
|
||||
she was logged in successfully. If an error occurred, the template is
|
||||
|
|
@ -80,7 +80,7 @@ notified about that, and the user is asked again::
|
|||
return redirect(url_for('show_entries'))
|
||||
return render_template('login.html', error=error)
|
||||
|
||||
The logout function, on the other hand, removes that key from the session
|
||||
The `logout` function, on the other hand, removes that key from the session
|
||||
again. We use a neat trick here: if you use the :meth:`~dict.pop` method
|
||||
of the dict and pass a second parameter to it (the default), the method
|
||||
will delete the key from the dictionary if present or do nothing when that
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue