Made grammar changes to the Tutorial.
This commit is contained in:
parent
8421c1ea0c
commit
86cc6f9806
10 changed files with 63 additions and 64 deletions
|
|
@ -3,9 +3,9 @@
|
||||||
Step 4: Request Database Connections
|
Step 4: Request Database Connections
|
||||||
------------------------------------
|
------------------------------------
|
||||||
|
|
||||||
Now we know how we can open database connections and use them for scripts,
|
Now we know how to open database connections and use them for scripts,
|
||||||
but how can we elegantly do that for requests? We will need the database
|
but how can we elegantly do that for requests? We will need the database
|
||||||
connection in all our functions so it makes sense to initialize them
|
connection in all our functions, so it makes sense to initialize them
|
||||||
before each request and shut them down afterwards.
|
before each request and shut them down afterwards.
|
||||||
|
|
||||||
Flask allows us to do that with the :meth:`~flask.Flask.before_request` and
|
Flask allows us to do that with the :meth:`~flask.Flask.before_request` and
|
||||||
|
|
@ -27,10 +27,10 @@ passed the response that will be sent to the client. They have to return
|
||||||
that response object or a different one. In this case we just return it
|
that response object or a different one. In this case we just return it
|
||||||
unchanged.
|
unchanged.
|
||||||
|
|
||||||
We store our current database connection on the special :data:`~flask.g`
|
We store our current database connection in the special :data:`~flask.g`
|
||||||
object that flask provides for us. This object stores information for one
|
object that Flask provides for us. This object stores information for one
|
||||||
request only and is available from within each function. Never store such
|
request only and is available from within each function. Never store such
|
||||||
things on other objects because this would not work with threaded
|
things in other objects because this would not work with threaded
|
||||||
environments. That special :data:`~flask.g` object does some magic behind
|
environments. That special :data:`~flask.g` object does some magic behind
|
||||||
the scenes to ensure it does the right thing.
|
the scenes to ensure it does the right thing.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ Step 3: Creating The Database
|
||||||
Flaskr is a database powered application as outlined earlier, and more
|
Flaskr is a database powered application as outlined earlier, and more
|
||||||
precisely, an application powered by a relational database system. Such
|
precisely, an application powered by a relational database system. Such
|
||||||
systems need a schema that tells them how to store that information. So
|
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
|
before starting the server for the first time, it's important to create
|
||||||
that schema.
|
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
|
||||||
|
|
@ -15,15 +15,15 @@ Such a schema can be created by piping the `schema.sql` file into the
|
||||||
sqlite3 /tmp/flaskr.db < schema.sql
|
sqlite3 /tmp/flaskr.db < schema.sql
|
||||||
|
|
||||||
The downside of this is that it requires the sqlite3 command to be
|
The downside of this is that it requires the sqlite3 command to be
|
||||||
installed which is not necessarily the case on every system. Also one has
|
installed, which is not necessarily the case on every system. Also, one has
|
||||||
to provide the path to the database there which leaves some place for
|
to provide the path to the database which leaves some place for
|
||||||
errors. It's a good idea to add a function that initializes the database
|
errors. It's a good idea to add a function to the application that
|
||||||
for you to the application.
|
initializes the database for you.
|
||||||
|
|
||||||
If you want to do that, you first have to import the
|
If you want to do that, you first have to import the
|
||||||
:func:`contextlib.closing` function from the contextlib package. If you
|
:func:`contextlib.closing` function from the contextlib package. If you
|
||||||
want to use Python 2.5 it's also necessary to enable the `with` statement
|
want to use Python 2.5, it's also necessary to enable the `with` statement
|
||||||
first (`__future__` imports must be the very first import)::
|
(`__future__` imports must be the very first import)::
|
||||||
|
|
||||||
from __future__ import with_statement
|
from __future__ import with_statement
|
||||||
from contextlib import closing
|
from contextlib import closing
|
||||||
|
|
@ -52,8 +52,8 @@ execute a complete script. Finally we only have to commit the changes.
|
||||||
SQLite 3 and other transactional databases will not commit unless you
|
SQLite 3 and other transactional databases will not commit unless you
|
||||||
explicitly tell it to.
|
explicitly tell it to.
|
||||||
|
|
||||||
Now it is possible to create a database by starting up a Python shell and
|
Now it is possible to create a database by importing and calling that function
|
||||||
importing and calling that function::
|
from within a Python shell::
|
||||||
|
|
||||||
>>> from flaskr import init_db
|
>>> from flaskr import init_db
|
||||||
>>> init_db()
|
>>> init_db()
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,12 @@ application::
|
||||||
/static
|
/static
|
||||||
/templates
|
/templates
|
||||||
|
|
||||||
The `flaskr` folder is not a python package, but just something where we
|
The `flaskr` folder is not a python package but just something where we
|
||||||
drop our files. Directly into this folder we will then put our database
|
drop our files. We will then put our database schema and main module
|
||||||
schema as well as main module in the following steps. The files inside
|
directly into this folder in the following steps. The files inside
|
||||||
the `static` folder are available to users of the application via `HTTP`.
|
the `static` folder are available to users of the application via `HTTP`.
|
||||||
This is the place where css and javascript files go. Inside the
|
This is the place where css and javascript files go. Inside the
|
||||||
`templates` folder Flask will look for `Jinja2`_ templates. The
|
`templates` folder, Flask will look for `Jinja2`_ templates. The
|
||||||
templates you create later in the tutorial will go in this directory.
|
templates you create later in the tutorial will go in this directory.
|
||||||
|
|
||||||
Continue with :ref:`tutorial-schema`.
|
Continue with :ref:`tutorial-schema`.
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ 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
|
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
|
simple microblog application. It only supports one user that can create
|
||||||
text-only entries and there are no feeds or comments, but it still
|
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
|
features everything you need to get started. We will use Flask along with
|
||||||
as database which comes out of the box with Python, so there is nothing
|
the SQLite database which is included with Python, so there is nothing
|
||||||
else you need.
|
else you need.
|
||||||
|
|
||||||
If you want the full sourcecode in advance or for comparison, check out
|
If you want the full sourcecode in advance or for comparison, check out
|
||||||
|
|
|
||||||
|
|
@ -3,25 +3,25 @@
|
||||||
Introducing Flaskr
|
Introducing Flaskr
|
||||||
==================
|
==================
|
||||||
|
|
||||||
We will call our blogging application flaskr here, feel free to chose a
|
We will call our blogging application flaskr. Feel free to chose a
|
||||||
less web-2.0-ish name ;) Basically we want it to do the following things:
|
less web-2.0-ish name. ;) Basically 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.
|
configuration. Only one user is supported.
|
||||||
2. when the user is logged in he or she can add new entries to the page
|
2. When the user is logged in he or she can add new entries to the page
|
||||||
consisting of a text-only title and some HTML for the text. This HTML
|
consisting of a text-only title and some HTML for the text. This HTML
|
||||||
is not sanitized because we trust the user here.
|
is not sanitized because we trust the user here.
|
||||||
3. the page shows all entries so far in reverse order (newest on top) and
|
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.
|
the user can add new ones from there if logged in.
|
||||||
|
|
||||||
We will be using SQLite3 directly for that application because it's good
|
We will be using SQLite3 directly because it's good enough for an application
|
||||||
enough for an application of that size. For larger applications however
|
of this size. For larger applications, however, it makes sense to use
|
||||||
it makes a lot of sense to use `SQLAlchemy`_ that handles database
|
`SQLAlchemy`_. Advantages of SQLAlchemy include handling database connections
|
||||||
connections in a more intelligent way, allows you to target different
|
in a more intelligent way, allowing you to target different relational
|
||||||
relational databases at once and more. You might also want to consider
|
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.
|
one of the popular NoSQL databases if your data is more suited for those.
|
||||||
|
|
||||||
Here a screenshot from the final application:
|
Here is a screenshot from the final application:
|
||||||
|
|
||||||
.. image:: ../_static/flaskr.png
|
.. image:: ../_static/flaskr.png
|
||||||
:align: center
|
:align: center
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ the just created `flaskr` folder:
|
||||||
);
|
);
|
||||||
|
|
||||||
This schema consists of a single table called `entries` and each row in
|
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 table has an `id`, a `title`, and a `text` field. The `id` serves as
|
||||||
automatically incrementing integer and a primary key, the other two are
|
the primary key and is an automatically incrementing integer. The other two
|
||||||
strings that must not be null.
|
fields are strings that must not be null.
|
||||||
|
|
||||||
Continue with :ref:`tutorial-setup`.
|
Continue with :ref:`tutorial-setup`.
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,12 @@
|
||||||
Step 2: Application Setup Code
|
Step 2: Application Setup Code
|
||||||
==============================
|
==============================
|
||||||
|
|
||||||
Now that we have the schema in place we can create the application module.
|
Now that we have the schema in place, we can create the application module.
|
||||||
Let's call it `flaskr.py` inside the `flaskr` folder. For starters we
|
Let's call it `flaskr.py` inside the `flaskr` folder. For starters, we
|
||||||
will add the imports we will need as well as the config section. For
|
will add the required imports as well as the config section. For
|
||||||
small applications it's a possibility to drop the configuration directly
|
small applications, such as this, the configuration can be dropped directly
|
||||||
into the module which we will be doing here. However a cleaner solution
|
into the application module. However, a cleaner solution would be to create
|
||||||
would be to create a separate `.ini` or `.py` file and load that or import
|
a separate `.ini` or `.py` file and load that or import the values from there.
|
||||||
the values from there.
|
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
|
|
@ -34,12 +33,11 @@ config from the same file::
|
||||||
|
|
||||||
:meth:`~flask.Config.from_object` will look at the given object (if it's a
|
:meth:`~flask.Config.from_object` will look at the given object (if it's a
|
||||||
string it will import it) and then look for all uppercase variables
|
string it will import it) and then look for all uppercase variables
|
||||||
defined there. In our case, the configuration we just wrote a few lines
|
defined there. In our case, :meth:`~flask.Config.from_object` finds the
|
||||||
of code above. You can also move that into a separate file.
|
configuration we just wrote a few lines of code above.
|
||||||
|
|
||||||
It is also a good idea to be able to load a configuration from a
|
It is also a good idea to be able to load a configuration from a
|
||||||
configurable file. This is what :meth:`~flask.Config.from_envvar` can
|
configurable file. This is the purpose of :meth:`~flask.Config.from_envvar`::
|
||||||
do::
|
|
||||||
|
|
||||||
app.config.from_envvar('FLASKR_SETTINGS', silent=True)
|
app.config.from_envvar('FLASKR_SETTINGS', silent=True)
|
||||||
|
|
||||||
|
|
@ -63,16 +61,17 @@ Python shell or a script. This will come in handy later.
|
||||||
def connect_db():
|
def connect_db():
|
||||||
return sqlite3.connect(app.config['DATABASE'])
|
return sqlite3.connect(app.config['DATABASE'])
|
||||||
|
|
||||||
Finally we just add a line to the bottom of the file that fires up the
|
Finally, we add a line to the bottom of the file that fires up the
|
||||||
server if we want to run that file as a standalone application::
|
server if we want to run that file as a standalone application::
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run()
|
app.run()
|
||||||
|
|
||||||
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. When you head over to the server you will get an 404
|
When you head over to your web browser you will get a 404
|
||||||
page not found error because we don't have any views yet. But we will
|
page not found error because we don't have any views yet. Not to worry,
|
||||||
focus on that a little later. First we should get the database working.
|
we'll create some views in a bit. But first we should get the database
|
||||||
|
working.
|
||||||
|
|
||||||
.. admonition:: Externally Visible Server
|
.. admonition:: Externally Visible Server
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
Step 6: The Templates
|
Step 6: The Templates
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
Now we should start working on the templates. If we request the URLs now
|
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
|
we would only get an exception that Flask cannot find the templates. The
|
||||||
templates are using `Jinja2`_ syntax and have autoescaping enabled by
|
templates are using `Jinja2`_ syntax and have autoescaping enabled by
|
||||||
default. This means that unless you mark a value in the code with
|
default. This means that unless you mark a value in the code with
|
||||||
|
|
@ -21,7 +21,7 @@ Put the following templates into the `templates` folder:
|
||||||
layout.html
|
layout.html
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
This template contains the HTML skeleton, the header and a link to log in
|
This template contains the HTML skeleton, the header, and a link to log in
|
||||||
(or log out if the user was already logged in). It also displays the
|
(or log out if the user was already logged in). It also displays the
|
||||||
flashed messages if there are any. The ``{% block body %}`` block can be
|
flashed messages if there are any. The ``{% block body %}`` block can be
|
||||||
replaced by a block of the same name (``body``) in a child template.
|
replaced by a block of the same name (``body``) in a child template.
|
||||||
|
|
@ -58,7 +58,7 @@ show_entries.html
|
||||||
This template extends the `layout.html` template from above to display the
|
This template extends the `layout.html` template from above to display the
|
||||||
messages. Note that the `for` loop iterates over the messages we passed
|
messages. Note that the `for` loop iterates over the messages we passed
|
||||||
in with the :func:`~flask.render_template` function. We also tell the
|
in with the :func:`~flask.render_template` function. We also tell the
|
||||||
form to submit to your `add_entry` function and use `POST` as `HTTP`
|
form to submit to the `add_entry` function and use `POST` as `HTTP`
|
||||||
method:
|
method:
|
||||||
|
|
||||||
.. sourcecode:: html+jinja
|
.. sourcecode:: html+jinja
|
||||||
|
|
@ -88,8 +88,7 @@ method:
|
||||||
login.html
|
login.html
|
||||||
----------
|
----------
|
||||||
|
|
||||||
Finally the login template which basically just displays a form to allow
|
Finally, the login template displays a form allowing the user to login:
|
||||||
the user to login:
|
|
||||||
|
|
||||||
.. sourcecode:: html+jinja
|
.. sourcecode:: html+jinja
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,5 +6,5 @@ Bonus: Testing the Application
|
||||||
Now that you have finished the application and everything works as
|
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
|
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
|
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.
|
documentation. Go there to see how easy it is to test Flask applications.
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,11 @@ Show Entries
|
||||||
This view shows all the entries stored in the database. It listens on the
|
This view shows all the entries stored in the database. It listens on the
|
||||||
root of the application and will select title and text from the database.
|
root of the application and will select title and text from the database.
|
||||||
The one with the highest id (the newest entry) will be on top. The rows
|
The one with the highest id (the newest entry) will be on top. The rows
|
||||||
returned from the cursor are tuples with the columns ordered like specified
|
returned from the cursor are tuples with the columns ordered as specified
|
||||||
in the select statement. This is good enough for small applications like
|
in the select statement. This is good enough for small applications such
|
||||||
here, but you might want to convert them into a dict. If you are
|
as flaskr. For larger applications, you might want to convert them into a
|
||||||
interested in how to do that, check out the :ref:`easy-querying` example.
|
dict. If you are interested in how to do that, check out the
|
||||||
|
:ref:`easy-querying` example.
|
||||||
|
|
||||||
The view function will pass the entries as dicts to the
|
The view function will pass the entries as dicts to the
|
||||||
`show_entries.html` template and return the rendered one::
|
`show_entries.html` template and return the rendered one::
|
||||||
|
|
@ -30,8 +31,8 @@ Add New Entry
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
This view lets the user add new entries if he's logged in. This only
|
This view lets the user add new entries if he's logged in. This only
|
||||||
responds to `POST` requests, the actual form is shown on the
|
responds to `POST` requests. The actual form is shown on the
|
||||||
`show_entries` page. If everything worked out well we will
|
`show_entries` page. If everything worked out well, we will
|
||||||
:func:`~flask.flash` an information message to the next request and
|
:func:`~flask.flash` an information message to the next request and
|
||||||
redirect back to the `show_entries` page::
|
redirect back to the `show_entries` page::
|
||||||
|
|
||||||
|
|
@ -51,8 +52,8 @@ present in the session and `True`).
|
||||||
.. admonition:: Security Note
|
.. admonition:: Security Note
|
||||||
|
|
||||||
Be sure to use question marks when building SQL statements, as done in the
|
Be sure to use question marks when building SQL statements, as done in the
|
||||||
example above. Otherwise, your app will be vulnerable to SQL injection when
|
example above. Otherwise, your app will be vulnerable to SQL injection
|
||||||
you use string formatting to build SQL statements.
|
when you use string formatting to build SQL statements.
|
||||||
See :ref:`sqlite3` for more.
|
See :ref:`sqlite3` for more.
|
||||||
|
|
||||||
Login and Logout
|
Login and Logout
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue