.. _sqlalchemy-pattern: SQLAlchemy во Flask =================== Многие люди для доступа к базам данных предпочитают использовать `SQLAlchemy`_. В этом случае для написания приложений на Flask больше подходят не модули, а пакеты, так как в этом случае можно поместить модели в отдельный модуль (:ref:`larger-applications`). Хоть это и не обязательно, но всё же имеет смысл. Есть четыре обычных способа использования SQLAlchemy. Остановимся на каждом из них подробнее: Расширение Flask-SQLAlchemy --------------------------- Поскольку SQLAlchemy - это обобщённый слой абстракции над базами данных и объектно-реляционное отображение, требующее предварительной настройки, существует расширение Flask, делающее всё необходимое за вас. Если нужно быстро начать работу, рекомендуем воспользоваться им. Расширение `Flask-SQLAlchemy`_ можно скачать из `PyPI `_. .. _Flask-SQLAlchemy: http://packages.python.org/Flask-SQLAlchemy/ 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 с объектом :data:`~flask.g` выше), то это потому что SQLAlchemy делает это самостоятельно при помощи :class:`~sqlalchemy.orm.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 '' % (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.query.filter(User.name == 'admin').first() .. _SQLAlchemy: http://www.sqlalchemy.org/ .. _declarative: http://www.sqlalchemy.org/docs/orm/extensions/declarative.html Ручное объектно-реляционное отображение --------------------------------------- Ручное объектно-реляционное отображение имеет некоторые преимущества и недостатки по сравнению с декларативным подходом, рассмотренным выше. Главное отличие заключается в том, что таблицы и классы определяются раздельно, а затем создаётся их взаимное отображение. Этот подход более гибок, однако и более трудоёмок. В целом он работает подобно декларативному подходу, поэтому убедитесь в том, что поделили ваше приложение на несколько модулей в пакете. Вот пример модуля `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 '' % (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' В метод :meth:`~sqlalchemy.engine.base.Connection.execute` можно также передавать строки с выражениями SQL: >>> engine.execute('select * from users where id = :1', [1]).first() (1, u'admin', u'admin@localhost') За более подробной информацией о SQLAlchemy обратитесь к `вебсайту `_. Примечание переводчика: В сети можно найти `русскоязычный вики-учебник по использованию SQLAlchemy: `_. `Оригинал этой страницы `_