forked from orbit-oss/flask
Proofreading the documentation
This commit is contained in:
parent
4ff9493e57
commit
a7ff9dbddd
8 changed files with 58 additions and 58 deletions
|
|
@ -8,11 +8,11 @@ designed for large scale applications and does not attempt to do so, but
|
|||
that does not mean you picked the wrong tool in the first place.
|
||||
|
||||
Flask is powered by Werkzeug and Jinja2, two libraries that are in use at
|
||||
a number of large websites out there and all Flask does is bringing those
|
||||
a number of large websites out there and all Flask does is bring those
|
||||
two together. Being a microframework, Flask is literally a single file.
|
||||
What that means for large applications is that it's probably a good idea
|
||||
to take the code from Flask and put it into a new module within the
|
||||
applications and expanding on that.
|
||||
applications and expand on that.
|
||||
|
||||
What Could Be Improved?
|
||||
-----------------------
|
||||
|
|
@ -20,12 +20,12 @@ What Could Be Improved?
|
|||
For instance it makes a lot of sense to change the way endpoints (the
|
||||
names of the functions / URL rules) are handled to also take the module
|
||||
name into account. Right now the function name is the URL name, but
|
||||
imagine you have a large applications consisting of multiple components.
|
||||
imagine you have a large application consisting of multiple components.
|
||||
In that case, it makes a lot of sense to use dotted names for the URL
|
||||
endpoints.
|
||||
|
||||
Here some suggestions how Flask can be modified to better accomodate large
|
||||
scale applications:
|
||||
Here are some suggestions for how Flask can be modified to better
|
||||
accomodate large-scale applications:
|
||||
|
||||
- implement dotted names for URL endpoints
|
||||
- get rid of the decorator function registering which causes a lot
|
||||
|
|
@ -35,7 +35,7 @@ scale applications:
|
|||
better solution would be to have one module with all URLs in there and
|
||||
specifing the target functions explicitly or by name and importing
|
||||
them when needed.
|
||||
- switch to explicit request object passing. This makes it more to type
|
||||
- switch to explicit request object passing. This requires more typing
|
||||
(because you now have something to pass around) but it makes it a
|
||||
whole lot easier to debug hairy situations and to test the code.
|
||||
- integrate the `Babel`_ i18n package or `SQLAlchemy`_ directly into the
|
||||
|
|
@ -44,14 +44,14 @@ scale applications:
|
|||
.. _Babel: http://babel.edgewall.org/
|
||||
.. _SQLAlchemy: http://www.sqlalchemy.org/
|
||||
|
||||
Why does not Flask do all that by Default?
|
||||
Why does Flask not do all that by Default?
|
||||
------------------------------------------
|
||||
|
||||
There is a huge difference between a small application that only has to
|
||||
handle a couple of requests per second and with an overall code complexity
|
||||
of less than 4000 lines of code or something of larger scale. At one
|
||||
of less than 4000 lines of code and something of larger scale. At some
|
||||
point it becomes important to integrate external systems, different
|
||||
storage backends and more.
|
||||
|
||||
If Flask was designed with all these contingencies in mind, it would be a
|
||||
much more complex framework and less easy to get started with.
|
||||
much more complex framework and harder to get started with.
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ Installing `mod_wsgi`
|
|||
If you don't have `mod_wsgi` installed yet you have to either install it using
|
||||
a package manager or compile it yourself.
|
||||
|
||||
The mod_wsgi `installation instructions`_ cover installation instructions for
|
||||
source installations on UNIX systems.
|
||||
The mod_wsgi `installation instructions`_ cover source installations on UNIX
|
||||
systems.
|
||||
|
||||
If you are using ubuntu / debian you can apt-get it and activate it as follows::
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ For most applications the following file should be sufficient::
|
|||
If you don't have a factory function for application creation but a singleton
|
||||
instance you can directly import that one as `application`.
|
||||
|
||||
Store that file somewhere where you will find it again (eg:
|
||||
Store that file somewhere that you will find it again (e.g.:
|
||||
`/var/www/yourapplication`) and make sure that `yourapplication` and all
|
||||
the libraries that are in use are on the python load path. If you don't
|
||||
want to install it system wide consider using a `virtual python`_ instance.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ Design Decisions in Flask
|
|||
=========================
|
||||
|
||||
If you are curious why Flask does certain things the way it does and not
|
||||
different, this section is for you. This should give you an idea about
|
||||
differently, this section is for you. This should give you an idea about
|
||||
some of the design decisions that may appear arbitrary and surprising at
|
||||
first, especially in direct comparison with other frameworks.
|
||||
|
||||
|
|
@ -44,10 +44,10 @@ something it can be very helpful to create a minimal application to test
|
|||
specific behavior. When the application object is deleted everything it
|
||||
allocated will be freed again.
|
||||
|
||||
Another thing that becomes possible with having an explicit object laying
|
||||
Another thing that becomes possible when you have an explicit object laying
|
||||
around in your code is that you can subclass the base class
|
||||
(:class:`~flask.Flask`) to alter specific behaviour. This would not be
|
||||
possible without hacks if the object was created ahead of time for you
|
||||
possible without hacks if the object were created ahead of time for you
|
||||
based on a class that is not exposed to you.
|
||||
|
||||
But there is another very important reason why Flask depends on an
|
||||
|
|
@ -83,23 +83,23 @@ that limitation that Jinja2 is *always* configured will probably go away,
|
|||
the decision to bundle one template engine and use that will not.
|
||||
|
||||
Template engines are like programming languages and each of those engines
|
||||
has a certain understandment about how things work. On the surface they
|
||||
has a certain understanding about how things work. On the surface they
|
||||
all work the same: you tell the engine to evaluate a template with a set
|
||||
of variables and take the return value as string.
|
||||
|
||||
But that's about where similarities end. Jinja2 for example has an
|
||||
extensive filter system, a certain way to do template inheritance, support
|
||||
for reusable blocks (macros) that can be used from inside templates and
|
||||
also from Python code, is using unicode for all operations, supports
|
||||
also from Python code, uses unicode for all operations, supports
|
||||
iterative template rendering, configurable syntax and more. On the other
|
||||
hand an engine like Genshi is based on XML stream evaluation, template
|
||||
inheritance by taking the availability of XPath into account and more.
|
||||
Mako on the other hand treats templates similar to Python modules.
|
||||
|
||||
When it comes to bridge a template engine with an application or framework
|
||||
there is more than just rendering templates. Flask uses Jinja2's
|
||||
extensive autoescaping support for instance. Also it provides ways to
|
||||
access macros from Jinja2 templates.
|
||||
When it comes to connecting a template engine with an application or
|
||||
framework there is more than just rendering templates. For instance,
|
||||
Flask uses Jinja2's extensive autoescaping support. Also it provides
|
||||
ways to access macros from Jinja2 templates.
|
||||
|
||||
A template abstraction layer that would not take the unique features of
|
||||
the template engines away is a science on its own and a too large
|
||||
|
|
@ -115,9 +115,9 @@ over to the Ruby side of web development there we have a protocol very
|
|||
similar to WSGI. Just that it's called Rack there, but besides that it
|
||||
looks very much like a WSGI rendition for Ruby. But nearly all
|
||||
applications in Ruby land do not work with Rack directly, but on top of a
|
||||
lirbary with the same name. This Rack library has two equivalents in
|
||||
library with the same name. This Rack library has two equivalents in
|
||||
Python: WebOb (formerly Paste) and Werkzeug. Paste is still around but
|
||||
from my understanding it's sortof deprecated in favour of WebOb. The
|
||||
from my understanding it's sort of deprecated in favour of WebOb. The
|
||||
development of WebOb and Werkzeug started side by side with similar ideas
|
||||
in mind: be a good implementation of WSGI for other applications to take
|
||||
advantage.
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ way and why there are multiple ways.
|
|||
|
||||
Flask depends on two external libraries: `Werkzeug
|
||||
<http://werkzeug.pocoo.org/>`_ and `Jinja2 <http://jinja.pocoo.org/2/>`_.
|
||||
The first on is responsible for interfacing WSGI the latter to render
|
||||
The first one is responsible for interfacing WSGI the latter for rendering
|
||||
templates. Now you are maybe asking, what is WSGI? WSGI is a standard
|
||||
in Python that is basically responsible for ensuring that your application
|
||||
is behaving in a specific way that you can run it on different
|
||||
is behaving in a specific way so that you can run it on different
|
||||
environments (for example on a local development server, on an Apache2, on
|
||||
lighttpd, on Google's App Engine or whatever you have in mind).
|
||||
|
||||
|
|
@ -26,10 +26,10 @@ Virtualenv is what you want to use during development and in production if
|
|||
you have shell access. So first: what does virtualenv do? If you are
|
||||
like me and you like Python, chances are you want to use it for another
|
||||
project as well. Now the more projects you have, the more likely it is
|
||||
that you will be working with different versions of Python itself or a
|
||||
library involved. Because let's face it: quite often libraries break
|
||||
backwards compatibility and it's unlikely that your application will
|
||||
not have any dependencies, that just won't happen. So virtualenv for the
|
||||
that you will be working with different versions of Python itself or at
|
||||
least an individual library. Because let's face it: quite often libraries
|
||||
break backwards compatibility and it's unlikely that your application will
|
||||
not have any dependencies, that just won't happen. So virtualenv to the
|
||||
rescue!
|
||||
|
||||
It basically makes it possible to have multiple side-by-side
|
||||
|
|
@ -47,7 +47,7 @@ or even better::
|
|||
|
||||
$ sudo pip install virtualenv
|
||||
|
||||
Changes are you have virtualenv installed on your system then. Maybe it's
|
||||
Chances are you have virtualenv installed on your system then. Maybe it's
|
||||
even in your package manager (on ubuntu try ``sudo apt-get install
|
||||
python-virtualenv``).
|
||||
|
||||
|
|
@ -152,7 +152,7 @@ Once you have done that it's important to add the `easy_install` command
|
|||
and other Python scripts to the path. To do that you have to add the
|
||||
Python installation's Script folder to the `PATH` variable.
|
||||
|
||||
To do that, click right on your "Computer" desktop icon and click
|
||||
To do that, right-click on your "Computer" desktop icon and click
|
||||
"Properties". On Windows Vista and Windows 7 then click on "Advanced System
|
||||
settings", on Windows XP click on the "Advanced" tab instead. Then click
|
||||
on the "Environment variables" button and double click on the "Path"
|
||||
|
|
@ -165,7 +165,7 @@ the following value::
|
|||
|
||||
;C:\Python26\Scripts
|
||||
|
||||
Then you are done. To check if it worked, open the cmd and execute
|
||||
Then you are done. To check that it worked, open the cmd and execute
|
||||
"easy_install". If you have UAC enabled it should prompt you for admin
|
||||
privileges.
|
||||
|
||||
|
|
|
|||
|
|
@ -48,12 +48,12 @@ What did we gain from this? Now we can restructure the application a bit
|
|||
into multiple modules. The only thing you have to remember is the
|
||||
following quick checklist:
|
||||
|
||||
1. the `Flask` application object creation have to be in the
|
||||
1. the `Flask` application object creation has to be in the
|
||||
`__init__.py` file. That way each module can import it safely and the
|
||||
`__name__` variable will resole to the correct package.
|
||||
`__name__` variable will resolve to the correct package.
|
||||
2. all the view functions (the ones with a :meth:`~flask.Flask.route`
|
||||
decorator on top) have to be imported when in the `__init__.py` file.
|
||||
Not the objects itself, but the module it is in. Do the importing at
|
||||
Not the object itself, but the module it is in. Do the importing at
|
||||
the *bottom* of the file.
|
||||
|
||||
Here an example `__init__.py`::
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ SQLAlchemy in Flask
|
|||
Many people prefer `SQLAlchemy`_ for database access. In this case it's
|
||||
encouraged to use a package instead of a module for your flask application
|
||||
and drop the models into a separate module (:ref:`larger-applications`).
|
||||
Although that is not necessary but makes a lot of sense.
|
||||
While that is not necessary, it makes a lot of sense.
|
||||
|
||||
There are three very common ways to use SQLAlchemy. I will outline each
|
||||
of them here:
|
||||
|
|
@ -52,7 +52,7 @@ automatically remove database sessions at the end of the request for you::
|
|||
db_session.remove()
|
||||
return response
|
||||
|
||||
Here an example model (put that into `models.py` for instance)::
|
||||
Here is an example model (put this into `models.py`, e.g.)::
|
||||
|
||||
from sqlalchemy import Column, Integer, String
|
||||
from yourapplication.database import Base
|
||||
|
|
@ -70,7 +70,7 @@ Here an example model (put that into `models.py` for instance)::
|
|||
def __repr__(self):
|
||||
return '<User %r>' % (self.name, self.email)
|
||||
|
||||
You can insert entries into the database like this then:
|
||||
You can insert entries into the database like this:
|
||||
|
||||
>>> from yourapplication.database import db_session
|
||||
>>> from yourapplication.models import User
|
||||
|
|
@ -95,11 +95,11 @@ Manual Object Relational Mapping
|
|||
Manual object relational mapping has a few upsides and a few downsides
|
||||
versus the declarative approach from above. The main difference is that
|
||||
you define tables and classes separately and map them together. It's more
|
||||
flexible but a little more to type. In general it works similar to the
|
||||
flexible but a little more to type. In general it works like the
|
||||
declarative approach, so make sure to also split up your application into
|
||||
multiple modules in a package.
|
||||
|
||||
Here the example `database.py` module for your application::
|
||||
Here is an example `database.py` module for your application::
|
||||
|
||||
from sqlalchemy import create_engine, MetaData
|
||||
from sqlalchemy.orm import scoped_session, sessionmaker
|
||||
|
|
@ -112,7 +112,7 @@ Here the example `database.py` module for your application::
|
|||
def init_db():
|
||||
metadata.create_all(bind=engine)
|
||||
|
||||
As for the declarative approach you need to close down the session after
|
||||
As for the declarative approach you need to close the session after
|
||||
each request. Put this into your application module::
|
||||
|
||||
from yourapplication.database import db_session
|
||||
|
|
@ -122,7 +122,7 @@ each request. Put this into your application module::
|
|||
db_session.remove()
|
||||
return response
|
||||
|
||||
Here an example table and model (put that into `models.py` for instance)::
|
||||
Here is an example table and model (put this into `models.py`)::
|
||||
|
||||
from sqlalchemy import Table, Column, Integer, String
|
||||
from sqlalchemy.orm import mapper
|
||||
|
|
@ -172,7 +172,7 @@ connection first so that we can use a transaction:
|
|||
|
||||
SQLAlchemy will automatically commit for us.
|
||||
|
||||
To query your database, yu use the engine directly or use a connection:
|
||||
To query your database, you use the engine directly or use a connection:
|
||||
|
||||
>>> users.select(users.c.id == 1).execute().first()
|
||||
(1, u'admin', u'admin@localhost')
|
||||
|
|
@ -183,7 +183,7 @@ These results are also dict-like tuples:
|
|||
>>> r['name']
|
||||
u'admin'
|
||||
|
||||
You can also pass string of SQL statements to the
|
||||
You can also pass strings of SQL statements to the
|
||||
:meth:`~sqlalchemy.engine.base.Connection.execute` method:
|
||||
|
||||
>>> engine.execute('select * from users where id = :1', [1]).first()
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@
|
|||
Using SQLite 3 with Flask
|
||||
=========================
|
||||
|
||||
In Flask you can implement opening of dabase connections at the beginning
|
||||
In Flask you can implement opening of database connections at the beginning
|
||||
of the request and closing at the end with the
|
||||
:meth:`~flask.Flask.before_request` and :meth:`~flask.Flask.after_request`
|
||||
decorators in combination with the special :class:`~flask.g` object.
|
||||
|
||||
So here a simple example how you can use SQLite 3 with Flask::
|
||||
So here a simple example of how you can use SQLite 3 with Flask::
|
||||
|
||||
import sqlite3
|
||||
from flask import g
|
||||
|
|
@ -70,7 +70,7 @@ Initial Schemas
|
|||
|
||||
Relational databases need schemas, so applications often ship a
|
||||
`schema.sql` file that creates the database. It's a good idea to provide
|
||||
a function that creates the database bases on that schema. This function
|
||||
a function that creates the database based on that schema. This function
|
||||
can do that for you::
|
||||
|
||||
from contextlib import closing
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@ Testing Flask Applications
|
|||
Not sure where that is coming from, and it's not entirely correct, but
|
||||
also not that far from the truth. Untested applications make it hard to
|
||||
improve existing code and developers of untested applications tend to
|
||||
become pretty paranoid. If an application however has automated tests you
|
||||
can savely change things and you will instantly know if your change broke
|
||||
become pretty paranoid. If an application however has automated tests, you
|
||||
can safely change things and you will instantly know if your change broke
|
||||
something.
|
||||
|
||||
Flask gives you a couple of ways to test applications. It mainly does
|
||||
that by exposing the Werkzeug test :class:`~werkzeug.Client` class to your
|
||||
code and handling the context locals for you. You can then use that with
|
||||
your favourite testing solution. In this documentation we will us the
|
||||
your favourite testing solution. In this documentation we will use the
|
||||
:mod:`unittest` package that comes preinstalled with each Python
|
||||
installation.
|
||||
|
||||
|
|
@ -50,13 +50,13 @@ In order to test that, we add a second module (
|
|||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
The code in the `setUp` function creates a new test client and initialize
|
||||
The code in the `setUp` function creates a new test client and initializes
|
||||
a new database. That function is called before each individual test function.
|
||||
What the test client does for us is giving us a simple interface to the
|
||||
What the test client does is give us a simple interface to the
|
||||
application. We can trigger test requests to the application and the
|
||||
client will also keep track of cookies for us.
|
||||
|
||||
Because SQLite3 is filesystem based we can easily use the tempfile module
|
||||
Because SQLite3 is filesystem-based we can easily use the tempfile module
|
||||
to create a temporary database and initialize it. Just make sure that you
|
||||
keep a reference to the :class:`~tempfile.NamedTemporaryFile` around (we
|
||||
store it as `self.db` because of that) so that the garbage collector does
|
||||
|
|
@ -112,20 +112,20 @@ Run it again and you should see one passing test::
|
|||
|
||||
OK
|
||||
|
||||
Of course you can submit forms with the test client as well which we will
|
||||
Of course you can submit forms with the test client as well, which we will
|
||||
use now to log our user in.
|
||||
|
||||
Logging In and Out
|
||||
------------------
|
||||
|
||||
The majority of the functionality of our application is only available for
|
||||
the administration user. So we need a way to log our test client into the
|
||||
the administration user. So we need a way to log our test client in to the
|
||||
application and out of it again. For that we fire some requests to the
|
||||
login and logout pages with the required form data (username and
|
||||
password). Because the login and logout pages redirect, we tell the
|
||||
client to `follow_redirects`.
|
||||
|
||||
Add the following two methods do your `FlaskrTestCase` class::
|
||||
Add the following two methods to your `FlaskrTestCase` class::
|
||||
|
||||
def login(self, username, password):
|
||||
return self.app.post('/login', data=dict(
|
||||
|
|
@ -137,7 +137,7 @@ Add the following two methods do your `FlaskrTestCase` class::
|
|||
return self.app.get('/logout', follow_redirects=True)
|
||||
|
||||
Now we can easily test if logging in and out works and that it fails with
|
||||
invalid credentials. Add this as new test to the class::
|
||||
invalid credentials. Add this new test to the class::
|
||||
|
||||
def test_login_logout(self):
|
||||
rv = self.login(flaskr.USERNAME, flaskr.PASSWORD)
|
||||
|
|
@ -165,7 +165,7 @@ like this::
|
|||
assert '<Hello>' in rv.data
|
||||
assert '<strong>HTML</strong> allowed here' in rv.data
|
||||
|
||||
Here we also check that HTML is allowed in the text but not in the title
|
||||
Here we check that HTML is allowed in the text but not in the title,
|
||||
which is the intended behavior.
|
||||
|
||||
Running that should now give us three passing tests::
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue