DevGang
Авторизоваться

FlaskSQLAlchemy

Расширение для поддержки SQLAlchemy в Flask

Flask-SQLAlchemy удобен в использовании, невероятно прост для базовых приложений и легко расширяется для более крупных приложений. Для получения полного руководства ознакомьтесь с документацией по API для класса SQLAlchemy.

Минимальное приложение

В общем случае наличия одного приложения Flask все что нужно для начала работы. Создайте приложение Flask, загрузите выбранную конфигурацию и затем создате объект SQLAlchemy, передав ему ссылку на приложение.

После создания этот объект содержит все функции и хелперы из sqlalchemy и sqlalchemy.orm. Кроме того, он предоставляет класс Model, который является декларативной базой, которую можно использовать для объявления моделей:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)


class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)

    def __repr__(self):
        return '<User %r>' % self.username

Для создания исходной базы данных просто импортируйте объект db из интерактивной оболочки Python и запустите метод SQLAlchemy.create_all() для создания таблиц и базы данных:

from yourapplication import db
db.create_all()

Теперь, чтобы создать несколько пользователей выполните следующее:

from yourapplication import User
admin = User(username='admin', email='admin@example.com')
guest = User(username='guest', email='guest@example.com')

Но они еще не в базе данных, поэтому давайте отправим их туда:

db.session.add(admin)
db.session.add(guest)
db.session.commit()

Доступ к данным в базе данных прост:

User.query.all()
# [<User u'admin'>, <User u'guest'>]

User.query.filter_by(username='admin').first()
# <User u'admin'>

Обратите внимание, как мы никогда не определяли метод __init__ в классе User. Это потому, что SQLAlchemy добавляет неявный конструктор ко всем классам модели, который принимает аргументы ключевых слов для всех своих столбцов и отношений. Если вы по какой-либо причине решите переопределить конструктор, обязательно продолжайте принимать **kwargs и вызывайте супер-конструктор с этими **kwargs, чтобы сохранить это поведение:

class Foo(db.Model):
    # ...
    def __init__(**kwargs):
        super(Foo, self).__init__(**kwargs)
    #...

Простые отношения

SQLAlchemy подключается к реляционным базам данных, и в этом отношении реляционные базы данных действительно хороши. Таким образом, у нас будет пример приложения, которое использует две таблицы, которые имеют отношение друг к другу:

from datetime import datetime


class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(80), nullable=False)
    body = db.Column(db.Text, nullable=False)
    pub_date = db.Column(db.DateTime, nullable=False,
        default=datetime.utcnow)

    category_id = db.Column(db.Integer, db.ForeignKey('category.id'),
        nullable=False)
    category = db.relationship('Category',
        backref=db.backref('posts', lazy=True))

    def __repr__(self):
        return '<Post %r>' % self.title


class Category(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50), nullable=False)

    def __repr__(self):
        return '<Category %r>' % self.name

Сначала давайте создадим несколько объектов:

py = Category(name='Python')
Post(title='Hello Python!', body='Python is pretty cool', category=py)
p = Post(title='Snakes', body='Ssssssss')
py.posts.append(p)
db.session.add(py)

Как видите, нет необходимости добавлять объекты Post в сеанс. Поскольку Категория является частью сеанса, все объекты, связанные с ней посредством отношений, также будут добавлены. Не имеет значения, вызывается ли db.session.add() до или после создания этих объектов. Связывание также может быть выполнено с любой стороны отношения, поэтому можно создать сообщение с категорией или добавить его в список сообщений этой категории.

Давайте посмотрим на сообщения:

py.posts
# [<Post 'Hello Python!'>, <Post 'Snakes'>]

Несмотря на то, что отложенная загрузка отношения быстрая, она может легко стать узким местом, когда вы в конечном итоге инициируете дополнительные запросы в цикле для нескольких объектов. В этом случае SQLAlchemy позволяет переопределить стратегию загрузки на уровне запроса. Если вам нужен один запрос для загрузки всех категорий и их сообщений, вы можете сделать это следующим образом:

from sqlalchemy.orm import joinedload

query = Category.query.options(joinedload('posts'))
for category in query:
     print(category, category.posts)
# <Category u'Python'> [<Post u'Hello Python!'>, <Post u'Snakes'>]

Если вы хотите получить объект запроса для этого отношения, вы можете сделать это с помощью with_parent(). Давайте условие в наш запрос:

Post.query.with_parent(py).filter(Post.title != 'Snakes').all()
# [<Post 'Hello Python!'>]

Чем отличается FlaskSQLAlchemy от SQLAlchemy

Единственное, что вам нужно знать по сравнению с простым SQLAlchemy:

  1. SQLAlchemy дает вам доступ к следующим вещам:
    • все функции и классы из sqlalchemy и sqlalchemy.orm
    • предварительно сконфигурированный сеанс с областью действия, называемый session
    • metadata
    • engine
    • методы SQLAlchemy.create_all() и SQLAlchemy.drop_all() для создания и удаления таблиц в соответствии с моделями.
    • Базовый класс модели, который является настроенной декларативной базой.
  2. Декларативный базовый класс Model ведет себя как обычный класс Python, но к нему прикреплен атрибут query, который можно использовать для запроса модели. (Model и BaseQuery)

  3. Вы должны выполнить session.commit(), но вам не нужно удалять его в конце запроса, Flask-SQLAlchemy сделает это за вас.

Комментарии
Чтобы оставить комментарий, необходимо авторизоваться