SQLAlchemy во Flask¶
Многие люди для доступа к базам данных предпочитают использовать SQLAlchemy. В этом случае для написания приложений на Flask больше подходят не модули, а пакеты, так как в этом случае можно поместить модели в отдельный модуль (Большие приложения во Flask). Хоть это и не обязательно, но всё же имеет смысл.
Есть четыре обычных способа использования SQLAlchemy. Остановимся на каждом из них подробнее:
Расширение Flask-SQLAlchemy¶
Поскольку SQLAlchemy - это обобщённый слой абстракции над базами данных и объектно-реляционное отображение, требующее предварительной настройки, существует расширение Flask, делающее всё необходимое за вас. Если нужно быстро начать работу, рекомендуем воспользоваться им.
Расширение Flask-SQLAlchemy можно скачать из PyPI.
Declarative¶
Расширение declarative в SQLAlchemy - это один из наиболее частых способов использования SQLAlchemy. Оно позволяет вам определять таблицы и модели одновременно, примерно так, как это делается в Django. В дополнение к следующему тексту рекомендуется обратиться к официальной документации по расширению declarative.
Вот пример модуля database.py для приложения:
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', convert_unicode=True)
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()
def init_db():
# Здесь нужно импортировать все модули, где могут быть определены модели,
# которые необходимым образом могут зарегистрироваться в метаданных.
# В противном случае их нужно будет импортировать до вызова init_db()
import yourapplication.models
Base.metadata.create_all(bind=engine)
Для определения собственных моделей наследуйте от класса Base, который
создан вышеприведённым кодом. Если вы удивлены, почему в этом примере не
нужно заботиться о потоках (как мы делали в примере для SQLite3 с объектом
g
выше), то это потому что SQLAlchemy делает это
самостоятельно при помощи scoped_session
.
Чтобы использовать SQLAlchemy в приложении декларативным образом, необходимо поместить в модуль вашего приложения следующий код. Flask автоматически удалит сеанс базы данных в конце запроса или при завершении приложения:
from yourapplication.database import db_session
@app.teardown_appcontext
def shutdown_session(exception=None):
db_session.remove()
Вот пример модели (поместите его, например, в models.py):
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)
Для создания базы данных можно воспользоваться функцией init_db:
>>> from yourapplication.database import init_db
>>> init_db()
Вот так можно добавить новые записи в базу данных:
>>> from yourapplication.database import db_session
>>> from yourapplication.models import User
>>> u = User('admin', 'admin@localhost')
>>> db_session.add(u)
>>> db_session.commit()
Пример запроса:
>>> User.query.all()
[<User u'admin'>]
>>> User.query.filter(User.name == 'admin').first()
<User u'admin'>
Ручное объектно-реляционное отображение¶
Ручное объектно-реляционное отображение имеет некоторые преимущества и недостатки по сравнению с декларативным подходом, рассмотренным выше. Главное отличие заключается в том, что таблицы и классы определяются раздельно, а затем создаётся их взаимное отображение. Этот подход более гибок, однако и более трудоёмок. В целом он работает подобно декларативному подходу, поэтому убедитесь в том, что поделили ваше приложение на несколько модулей в пакете.
Вот пример модуля database.py для вашего приложения:
from sqlalchemy import create_engine, MetaData
from sqlalchemy.orm import scoped_session, sessionmaker
engine = create_engine('sqlite:////tmp/test.db', convert_unicode=True)
metadata = MetaData()
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
def init_db():
metadata.create_all(bind=engine)
Как и при декларативном подходе, вам необходимо закрывать сеанс после каждого запроса или завершения контекста приложения. Поместите следующие строки в модуль вашего приложения:
from yourapplication.database import db_session
@app.teardown_appcontext
def shutdown_session(exception=None):
db_session.remove()
Вот пример таблицы и модели (поместите их в models.py):
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):
return '<User %r>' % (self.name)
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)
Запрос и вставка записей делается точно так же, как в примере выше.
Слой абстракции над SQL¶
Если вы хотите использовать только слой абстракции к базам данных (и SQL), вам потребуется только объект engine:
from sqlalchemy import create_engine, MetaData
engine = create_engine('sqlite:////tmp/test.db', convert_unicode=True)
metadata = MetaData(bind=engine)
Теперь можно объявить таблицы в коде, как в примере выше или автоматически загрузить их:
from sqlalchemy import Table
users = Table('users', metadata, autoload=True)
Чтобы вставить данные, вы можете воспользоваться методом insert. Прежде чем совершить транзакцию, необходимо сначала получить подключение:
>>> con = engine.connect()
>>> con.execute(users.insert(), name='admin', email='admin@localhost')
SQLAlchemy автоматически подтвердит транзакцию.
Для выполнения запросов можно воспользоваться напрямую объектом engine, либо использовать подключение:
>>> users.select(users.c.id == 1).execute().first()
(1, u'admin', u'admin@localhost')
С результатом запроса можно обращаться как со словарём:
>>> r = users.select(users.c.id == 1).execute().first()
>>> r['name']
u'admin'
В метод execute()
можно также
передавать строки с выражениями SQL:
>>> engine.execute('select * from users where id = :1', [1]).first()
(1, u'admin', u'admin@localhost')
За более подробной информацией о SQLAlchemy обратитесь к вебсайту.
Примечание переводчика:
В сети можно найти русскоязычный вики-учебник по использованию SQLAlchemy:.