SQLAlchemy в Flask
Многие предпочитают SQLAlchemy для доступа к базам данных. В этом случае рекомендуется использовать пакет вместо модуля для вашего приложения Flask и поместить модели в отдельный модуль (Большие приложения как пакеты). Хотя это необязательно, это имеет большой смысл.
Существует четыре очень распространённых способа использования SQLAlchemy. Я изложу каждый из них здесь:
Расширение Flask-SQLAlchemy
Поскольку SQLAlchemy — это распространённый абстрактный слой баз данных и объект-реляционный маппер, требующий небольших усилий по настройке, существует расширение Flask, которое обрабатывает это за вас. Это рекомендуется, если вы хотите быстро начать работу.
Вы можете загрузить Flask-SQLAlchemy с PyPI.
Декларативный
Декларативное расширение в SQLAlchemy — это наиболее современный метод использования SQLAlchemy. Оно позволяет определять таблицы и модели в одном шаге, аналогично тому, как работает Django. В дополнение к следующему тексту я рекомендую ознакомиться с официальной документацией по декларативному расширению.
Вот пример 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')
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()
def init_db():
# 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
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 f'<User {self.name!r}>'
Чтобы создать базу данных, вы можете использовать функцию 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 'admin'>] >>> User.query.filter(User.name == 'admin').first() <User 'admin'>
Ручное отображение объектов-отношений
Ручное отображение объектов-отношений имеет несколько преимуществ и недостатков по сравнению с декларативным подходом выше. Основное различие заключается в том, что вы определяете таблицы и классы отдельно и сопоставляете их вместе. Это более гибко, но требует больше работы. В целом, оно работает так же, как и декларативный подход, поэтому убедитесь, что вы также разделили своё приложение на несколько модулей в пакете.
Вот пример database.py модуля для вашего приложения:
from sqlalchemy import create_engine, MetaData
from sqlalchemy.orm import scoped_session, sessionmaker
engine = create_engine('sqlite:////tmp/test.db')
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 f'<User {self.name!r}>'
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), вам в основном нужен только движок:
from sqlalchemy import create_engine, MetaData, Table
engine = create_engine('sqlite:////tmp/test.db')
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 автоматически выполнит коммит за нас.
Для запроса к вашей базе данных используйте движок напрямую или подключение:
>>> users.select(users.c.id == 1).execute().first() (1, 'admin', 'admin@localhost')
Эти результаты также похожи на кортежи словарей:
>>> r = users.select(users.c.id == 1).execute().first() >>> r['name'] 'admin'
Вы также можете передавать строки SQL-запросов методу execute():
>>> engine.execute('select * from users where id = :1', [1]).first()
(1, 'admin', 'admin@localhost')
Для получения дополнительной информации о SQLAlchemy посетите сайт.
© 2007–2022 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/2.1.x/patterns/sqlalchemy/