| 
									
										
										
										
											2010-04-18 19:35:40 +08:00
										 |  |  | .. _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 models into a separate module (:ref:`larger-applications`).
 | 
					
						
							| 
									
										
										
										
											2010-04-20 12:25:51 +08:00
										 |  |  | While that is not necessary, it makes a lot of sense.
 | 
					
						
							| 
									
										
										
										
											2010-04-18 19:35:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-01 07:22:46 +08:00
										 |  |  | There are four very common ways to use SQLAlchemy.  I will outline each
 | 
					
						
							| 
									
										
										
										
											2010-04-18 19:35:40 +08:00
										 |  |  | of them here:
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-01 07:22:46 +08:00
										 |  |  | Flask-SQLAlchemy Extension
 | 
					
						
							|  |  |  | --------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Because SQLAlchemy is a common database abstraction layer and object
 | 
					
						
							|  |  |  | relational mapper that requires a little bit of configuration effort,
 | 
					
						
							|  |  |  | there is a Flask extension that handles that for you.  This is recommended
 | 
					
						
							|  |  |  | if you want to get started quickly.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | You can download `Flask-SQLAlchemy`_ from `PyPI
 | 
					
						
							| 
									
										
										
										
											2018-04-13 13:54:11 +08:00
										 |  |  | <https://pypi.org/project/Flask-SQLAlchemy/>`_.
 | 
					
						
							| 
									
										
										
										
											2010-07-01 07:22:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-24 06:37:51 +08:00
										 |  |  | .. _Flask-SQLAlchemy: https://flask-sqlalchemy.palletsprojects.com/
 | 
					
						
							| 
									
										
										
										
											2010-07-01 07:22:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-18 19:35:40 +08:00
										 |  |  | 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.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-27 12:27:44 +08:00
										 |  |  | Here's the example :file:`database.py` module for your application::
 | 
					
						
							| 
									
										
										
										
											2010-04-18 19:35:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     from sqlalchemy import create_engine
 | 
					
						
							|  |  |  |     from sqlalchemy.orm import scoped_session, sessionmaker
 | 
					
						
							|  |  |  |     from sqlalchemy.ext.declarative import declarative_base
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-04 01:58:07 +08:00
										 |  |  |     engine = create_engine('sqlite:////tmp/test.db', convert_unicode=True)
 | 
					
						
							| 
									
										
										
										
											2010-04-18 19:35:40 +08:00
										 |  |  |     db_session = scoped_session(sessionmaker(autocommit=False,
 | 
					
						
							|  |  |  |                                              autoflush=False,
 | 
					
						
							| 
									
										
										
										
											2012-09-04 11:51:45 +08:00
										 |  |  |                                              bind=engine))
 | 
					
						
							| 
									
										
										
										
											2010-04-18 19:35:40 +08:00
										 |  |  |     Base = declarative_base()
 | 
					
						
							|  |  |  |     Base.query = db_session.query_property()
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def init_db():
 | 
					
						
							| 
									
										
										
										
											2011-01-14 05:18:49 +08:00
										 |  |  |         # import all modules here that might define models so that
 | 
					
						
							|  |  |  |         # they will be registered properly on the metadata.  Otherwise
 | 
					
						
							|  |  |  |         # you will have to import them first before calling init_db()
 | 
					
						
							|  |  |  |         import yourapplication.models
 | 
					
						
							| 
									
										
										
										
											2010-04-18 19:35:40 +08:00
										 |  |  |         Base.metadata.create_all(bind=engine)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To define your models, just subclass the `Base` class that was created by
 | 
					
						
							|  |  |  | the code above.  If you are wondering why we don't have to care about
 | 
					
						
							|  |  |  | threads here (like we did in the SQLite3 example above with the
 | 
					
						
							|  |  |  | :data:`~flask.g` object): that's because SQLAlchemy does that for us
 | 
					
						
							|  |  |  | already with the :class:`~sqlalchemy.orm.scoped_session`.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To use SQLAlchemy in a declarative way with your application, you just
 | 
					
						
							|  |  |  | have to put the following code into your application module.  Flask will
 | 
					
						
							| 
									
										
										
										
											2013-06-07 22:42:49 +08:00
										 |  |  | automatically remove database sessions at the end of the request or
 | 
					
						
							|  |  |  | when the application shuts down::
 | 
					
						
							| 
									
										
										
										
											2010-04-18 19:35:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     from yourapplication.database import db_session
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-07 22:42:49 +08:00
										 |  |  |     @app.teardown_appcontext
 | 
					
						
							| 
									
										
										
										
											2011-05-28 02:21:41 +08:00
										 |  |  |     def shutdown_session(exception=None):
 | 
					
						
							| 
									
										
										
										
											2010-04-18 19:35:40 +08:00
										 |  |  |         db_session.remove()
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 11:45:22 +08:00
										 |  |  | Here is an example model (put this into :file:`models.py`, e.g.)::
 | 
					
						
							| 
									
										
										
										
											2010-04-18 19:35:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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):
 | 
					
						
							| 
									
										
										
										
											2019-10-26 14:19:00 +08:00
										 |  |  |             return f'<User {self.name!r}>'
 | 
					
						
							| 
									
										
										
										
											2010-04-18 19:35:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-14 05:18:49 +08:00
										 |  |  | To create the database you can use the `init_db` function:
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | >>> from yourapplication.database import init_db
 | 
					
						
							|  |  |  | >>> init_db()
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-20 12:25:51 +08:00
										 |  |  | You can insert entries into the database like this:
 | 
					
						
							| 
									
										
										
										
											2010-04-18 19:35:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | >>> 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'>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-11 17:43:11 +08:00
										 |  |  | .. _SQLAlchemy: https://www.sqlalchemy.org/
 | 
					
						
							| 
									
										
										
										
											2010-04-18 19:35:40 +08:00
										 |  |  | .. _declarative:
 | 
					
						
							| 
									
										
										
										
											2017-02-11 17:43:11 +08:00
										 |  |  |    https://docs.sqlalchemy.org/en/latest/orm/extensions/declarative/
 | 
					
						
							| 
									
										
										
										
											2010-04-18 19:35:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Manual Object Relational Mapping
 | 
					
						
							|  |  |  | --------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-19 00:29:55 +08:00
										 |  |  | 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
 | 
					
						
							| 
									
										
										
										
											2010-04-20 12:25:51 +08:00
										 |  |  | flexible but a little more to type.  In general it works like the
 | 
					
						
							| 
									
										
										
										
											2010-04-19 00:29:55 +08:00
										 |  |  | declarative approach, so make sure to also split up your application into
 | 
					
						
							|  |  |  | multiple modules in a package.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 11:45:22 +08:00
										 |  |  | Here is an example :file:`database.py` module for your application::
 | 
					
						
							| 
									
										
										
										
											2010-04-19 00:29:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     from sqlalchemy import create_engine, MetaData
 | 
					
						
							|  |  |  |     from sqlalchemy.orm import scoped_session, sessionmaker
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-04 01:58:07 +08:00
										 |  |  |     engine = create_engine('sqlite:////tmp/test.db', convert_unicode=True)
 | 
					
						
							| 
									
										
										
										
											2010-04-19 00:29:55 +08:00
										 |  |  |     metadata = MetaData()
 | 
					
						
							|  |  |  |     db_session = scoped_session(sessionmaker(autocommit=False,
 | 
					
						
							|  |  |  |                                              autoflush=False,
 | 
					
						
							| 
									
										
										
										
											2012-09-04 11:51:45 +08:00
										 |  |  |                                              bind=engine))
 | 
					
						
							| 
									
										
										
										
											2010-04-19 00:29:55 +08:00
										 |  |  |     def init_db():
 | 
					
						
							|  |  |  |         metadata.create_all(bind=engine)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-02 09:52:54 +08:00
										 |  |  | As in the declarative approach, you need to close the session after
 | 
					
						
							| 
									
										
										
										
											2013-06-07 22:42:49 +08:00
										 |  |  | each request or application context shutdown.  Put this into your
 | 
					
						
							|  |  |  | application module::
 | 
					
						
							| 
									
										
										
										
											2010-04-19 00:29:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     from yourapplication.database import db_session
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-07 22:42:49 +08:00
										 |  |  |     @app.teardown_appcontext
 | 
					
						
							| 
									
										
										
										
											2011-05-28 02:21:41 +08:00
										 |  |  |     def shutdown_session(exception=None):
 | 
					
						
							| 
									
										
										
										
											2010-04-19 00:29:55 +08:00
										 |  |  |         db_session.remove()
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 11:45:22 +08:00
										 |  |  | Here is an example table and model (put this into :file:`models.py`)::
 | 
					
						
							| 
									
										
										
										
											2010-04-19 00:29:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     from sqlalchemy import Table, Column, Integer, String
 | 
					
						
							|  |  |  |     from sqlalchemy.orm import mapper
 | 
					
						
							|  |  |  |     from yourapplication.database import metadata, db_session
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class User(object):
 | 
					
						
							|  |  |  |         query = db_session.query_property()
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def __init__(self, name=None, email=None):
 | 
					
						
							|  |  |  |             self.name = name
 | 
					
						
							|  |  |  |             self.email = email
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def __repr__(self):
 | 
					
						
							| 
									
										
										
										
											2019-10-26 14:19:00 +08:00
										 |  |  |             return f'<User {self.name!r}>'
 | 
					
						
							| 
									
										
										
										
											2010-04-19 00:29:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     users = Table('users', metadata,
 | 
					
						
							|  |  |  |         Column('id', Integer, primary_key=True),
 | 
					
						
							|  |  |  |         Column('name', String(50), unique=True),
 | 
					
						
							|  |  |  |         Column('email', String(120), unique=True)
 | 
					
						
							|  |  |  |     )
 | 
					
						
							|  |  |  |     mapper(User, users)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Querying and inserting works exactly the same as in the example above.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-18 19:35:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | SQL Abstraction Layer
 | 
					
						
							|  |  |  | ---------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-19 00:29:55 +08:00
										 |  |  | If you just want to use the database system (and SQL) abstraction layer
 | 
					
						
							|  |  |  | you basically only need the engine::
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-31 00:48:49 +08:00
										 |  |  |     from sqlalchemy import create_engine, MetaData, Table
 | 
					
						
							| 
									
										
										
										
											2010-04-19 00:29:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-04 01:58:07 +08:00
										 |  |  |     engine = create_engine('sqlite:////tmp/test.db', convert_unicode=True)
 | 
					
						
							| 
									
										
										
										
											2010-04-19 00:29:55 +08:00
										 |  |  |     metadata = MetaData(bind=engine)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Then you can either declare the tables in your code like in the examples
 | 
					
						
							|  |  |  | above, or automatically load them::
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-23 02:37:35 +08:00
										 |  |  |     from sqlalchemy import Table
 | 
					
						
							| 
									
										
										
										
											2014-07-24 23:03:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-19 00:29:55 +08:00
										 |  |  |     users = Table('users', metadata, autoload=True)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To insert data you can use the `insert` method.  We have to get a
 | 
					
						
							|  |  |  | connection first so that we can use a transaction:
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | >>> con = engine.connect()
 | 
					
						
							| 
									
										
										
										
											2012-09-04 11:51:45 +08:00
										 |  |  | >>> con.execute(users.insert(), name='admin', email='admin@localhost')
 | 
					
						
							| 
									
										
										
										
											2010-04-19 00:29:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | SQLAlchemy will automatically commit for us.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-20 12:25:51 +08:00
										 |  |  | To query your database, you use the engine directly or use a connection:
 | 
					
						
							| 
									
										
										
										
											2010-04-19 00:29:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | >>> users.select(users.c.id == 1).execute().first()
 | 
					
						
							|  |  |  | (1, u'admin', u'admin@localhost')
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | These results are also dict-like tuples:
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | >>> r = users.select(users.c.id == 1).execute().first()
 | 
					
						
							|  |  |  | >>> r['name']
 | 
					
						
							|  |  |  | u'admin'
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-20 12:25:51 +08:00
										 |  |  | You can also pass strings of SQL statements to the
 | 
					
						
							| 
									
										
										
										
											2010-04-19 00:29:55 +08:00
										 |  |  | :meth:`~sqlalchemy.engine.base.Connection.execute` method:
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | >>> engine.execute('select * from users where id = :1', [1]).first()
 | 
					
						
							|  |  |  | (1, u'admin', u'admin@localhost')
 | 
					
						
							| 
									
										
										
										
											2010-04-19 08:24:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | For more information about SQLAlchemy, head over to the
 | 
					
						
							| 
									
										
										
										
											2017-02-11 17:43:11 +08:00
										 |  |  | `website <https://www.sqlalchemy.org/>`_.
 |