Перевод статьи: SQLAlchemy in Flask
Автор: Армин Роначер (Armin Ronacher)
Многие люди предпочитают использовать SQLAlchemy для доступа к базам данных. В этом случае для написания приложений на Flask больше подходят пакеты вместо модулей, так как в этом случае можно поместить модели в отдельный модуль (Большие приложения). Хотя это и не является необходимым, это имеет смысл.
Есть четыре обычных способа использования SQLAlchemy. Остановимся на каждом из них подробнее:
Поскольку SQLAlchemy - это обобщённый слой абстракции над базами данных и объектно-реляционное отображение, требующее предварительной настройки, существует расширение Flask, делающее всё необходимое за вас. Если нужно быстро начать работу, рекомендуем воспользоваться им.
Расширение Flask-SQLAlchemy можно скачать из PyPI.
Расширение 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_request 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_request 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), вам потребуется только объект engine:
from sqlalchemy import create_engine, MetaData engine = create_engine('sqlite:////tmp/test.db', convert_unicode=True) metadata = MetaData(bind=engine)
Теперь можно объявить таблицы в коде, как в примере выше или автоматически загрузить их:
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: SQLAlchemy - викиучебник.
Этот и другие переводы можно найти на сайте проекта перевода документации по Flask. Автор проекта - Виталий Кузьмин aka ferm32.