|
|
@ -1,7 +1,7 @@ |
|
|
|
.. _patterns: |
|
|
|
.. _patterns: |
|
|
|
|
|
|
|
|
|
|
|
Patterns in Flask |
|
|
|
Patterns for Flask |
|
|
|
================= |
|
|
|
================== |
|
|
|
|
|
|
|
|
|
|
|
Certain things are common enough that the changes are high you will find |
|
|
|
Certain things are common enough that the changes are high you will find |
|
|
|
them in most web applications. For example quite a lot of applications |
|
|
|
them in most web applications. For example quite a lot of applications |
|
|
@ -10,10 +10,93 @@ changes are they will open a database connection at the beginning of the |
|
|
|
request and get the information of the currently logged in user. At the |
|
|
|
request and get the information of the currently logged in user. At the |
|
|
|
end of the request, the database connection is closed again. |
|
|
|
end of the request, the database connection is closed again. |
|
|
|
|
|
|
|
|
|
|
|
In Flask you can implement such things with the |
|
|
|
|
|
|
|
:meth:`~flask.Flask.before_request` and |
|
|
|
.. _larger-applications: |
|
|
|
:meth:`~flask.Flask.after_request` decorators in combination with the |
|
|
|
|
|
|
|
special :class:`~flask.g` object. |
|
|
|
Larger Applications |
|
|
|
|
|
|
|
------------------- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
For larger applications it's a good idea to use a package instead of a |
|
|
|
|
|
|
|
module. That is quite simple. Imagine a small application looks like |
|
|
|
|
|
|
|
this:: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/yourapplication |
|
|
|
|
|
|
|
/yourapplication.py |
|
|
|
|
|
|
|
/static |
|
|
|
|
|
|
|
/style.css |
|
|
|
|
|
|
|
/templates |
|
|
|
|
|
|
|
layout.html |
|
|
|
|
|
|
|
index.html |
|
|
|
|
|
|
|
login.html |
|
|
|
|
|
|
|
... |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
To convert that into a larger one, just create a new folder |
|
|
|
|
|
|
|
`yourapplication` inside the existing one and move everything below it. |
|
|
|
|
|
|
|
Then rename `yourapplication.py` to `__init__.py`. (Make sure to delete |
|
|
|
|
|
|
|
all `.pyc` files first, otherwise things would most likely break) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
You should then end up with something like that:: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/yourapplication |
|
|
|
|
|
|
|
/yourapplication |
|
|
|
|
|
|
|
/__init__.py |
|
|
|
|
|
|
|
/static |
|
|
|
|
|
|
|
/style.css |
|
|
|
|
|
|
|
/templates |
|
|
|
|
|
|
|
layout.html |
|
|
|
|
|
|
|
index.html |
|
|
|
|
|
|
|
login.html |
|
|
|
|
|
|
|
... |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
But how do you run your application now? The naive ``python |
|
|
|
|
|
|
|
yourapplication/__init__.py`` will not work. Let's just say that Python |
|
|
|
|
|
|
|
does not want modules in packages to be the startup file. But that is not |
|
|
|
|
|
|
|
a big problem, just add a new file called `runserver.py` next to the inner |
|
|
|
|
|
|
|
`yourapplication` folder with the following contents:: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from yourapplication import app |
|
|
|
|
|
|
|
app.run(debug=True) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
`__init__.py` file. That way each module can import it safely and the |
|
|
|
|
|
|
|
`__name__` variable will resole 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 |
|
|
|
|
|
|
|
the *bottom* of the file. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Here an example `__init__.py`:: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from flask import Flask |
|
|
|
|
|
|
|
app = Flask(__name__) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import yourapplication.views |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
And this is what `views.py` would look like:: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from yourapplication import app |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/') |
|
|
|
|
|
|
|
def index(): |
|
|
|
|
|
|
|
return 'Hello World!' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.. admonition:: Circular Imports |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Every Python programmer hates it, and yet we just did that: circular |
|
|
|
|
|
|
|
imports (That's when one module depends on another one. In this case |
|
|
|
|
|
|
|
`views.py` depends on `__init__.py`). Be advised that this is a bad |
|
|
|
|
|
|
|
idea in general but here it is actually fine. The reason for this is |
|
|
|
|
|
|
|
that we are not actually using the views in `__init__.py` and just |
|
|
|
|
|
|
|
ensuring the module is imported and we are doing that at the bottom of |
|
|
|
|
|
|
|
the file. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
There are still some problems with that approach but if you want to use |
|
|
|
|
|
|
|
decorators there is no way around that. Check out the |
|
|
|
|
|
|
|
:ref:`becomingbig` section for some inspiration how to deal with that. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.. _database-pattern: |
|
|
|
.. _database-pattern: |
|
|
@ -21,6 +104,11 @@ special :class:`~flask.g` object. |
|
|
|
Using SQLite 3 with Flask |
|
|
|
Using SQLite 3 with Flask |
|
|
|
------------------------- |
|
|
|
------------------------- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
In Flask you can implement opening of dabase 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 how you can use SQLite 3 with Flask:: |
|
|
|
|
|
|
|
|
|
|
|
import sqlite3 |
|
|
|
import sqlite3 |
|
|
@ -99,6 +187,95 @@ You can then create such a database from the python shell: |
|
|
|
>>> from yourapplication import init_db |
|
|
|
>>> from yourapplication import init_db |
|
|
|
>>> init_db() |
|
|
|
>>> init_db() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.. _sqlalchemy-pattern: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 modules into a separate module (:ref:`larger-applications`). |
|
|
|
|
|
|
|
Although that is not necessary but makes a lot of sense. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
There are three very common ways to use SQLAlchemy. I will outline each |
|
|
|
|
|
|
|
of them here: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Declarative |
|
|
|
|
|
|
|
``````````` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The declarative extension in SQLAlchemy is the most recent method of using |
|
|
|
|
|
|
|
SQLAlchemy. It allows you to define tables and models in one go, similar |
|
|
|
|
|
|
|
to how Django works. In addition to the following text I recommend the |
|
|
|
|
|
|
|
official documentation on the `declarative`_ extension. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Here the example `database.py` module for your application:: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from sqlalchemy import create_engine |
|
|
|
|
|
|
|
from sqlalchemy.orm import scoped_session, sessionmaker |
|
|
|
|
|
|
|
from sqlalchemy.ext.declarative import declarative_base |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
engine = create_engine('sqlite:////tmp/test.db') |
|
|
|
|
|
|
|
db_session = scoped_session(sessionmaker(autocommit=False, |
|
|
|
|
|
|
|
autoflush=False, |
|
|
|
|
|
|
|
bind=engine)) |
|
|
|
|
|
|
|
Base = declarative_base() |
|
|
|
|
|
|
|
Base.query = db_session.query_property() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def init_db(): |
|
|
|
|
|
|
|
Base.metadata.create_all(bind=engine) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
To define your models, subclass the `Base` class the above code generated. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
To use SQLAlchemy in a declarative way with your application, you just |
|
|
|
|
|
|
|
have to put the following code into your application module Flask will |
|
|
|
|
|
|
|
automatically remove database sessions at the end of the request for you:: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from yourapplication.database import db_session |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.after_request |
|
|
|
|
|
|
|
def shutdown_session(response): |
|
|
|
|
|
|
|
db_session.remove() |
|
|
|
|
|
|
|
return response |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Here an example model (put that into `models.py` for instance):: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from sqlalchemy import Column, Integer, String |
|
|
|
|
|
|
|
from yourapplication.database import Base |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class User(Base): |
|
|
|
|
|
|
|
__tablename__ = 'users' |
|
|
|
|
|
|
|
id = Column(Integer, primary_key=True) |
|
|
|
|
|
|
|
name = Column(String(50), unique=True) |
|
|
|
|
|
|
|
email = Column(String(120), unique=True) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, name=None, email=None): |
|
|
|
|
|
|
|
self.name = name |
|
|
|
|
|
|
|
self.email = email |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __repr__(self): |
|
|
|
|
|
|
|
return '<User %r>' % (self.name, self.email) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
You can insert entries into the database like this then: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>>> from yourapplication.database import db_session |
|
|
|
|
|
|
|
>>> from yourapplication.models import User |
|
|
|
|
|
|
|
>>> u = User('admin', 'admin@localhost') |
|
|
|
|
|
|
|
>>> db_session.add(u) |
|
|
|
|
|
|
|
>>> db_session.commit() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Querying is simple as well: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>>> User.query.all() |
|
|
|
|
|
|
|
[<User u'admin'>] |
|
|
|
|
|
|
|
>>> User.query.filter(User.name == 'admin').first() |
|
|
|
|
|
|
|
<User u'admin'> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.. _SQLAlchemy: http://www.sqlalchemy.org/ |
|
|
|
|
|
|
|
.. _declarative: |
|
|
|
|
|
|
|
http://www.sqlalchemy.org/docs/reference/ext/declarative.html |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.. _template-inheritance: |
|
|
|
.. _template-inheritance: |
|
|
|
|
|
|
|
|
|
|
|
Template Inheritance |
|
|
|
Template Inheritance |
|
|
|