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

FlaskSQLAlchemy

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

Flask-SQLAlchemy определяет разумные значения по умолчанию. Однако иногда требуется настройка. Существуют различные способы настройки определения и взаимодействия моделей.

Эти настройки применяются при создании объекта SQLAlchemy и распространяются на все модели, производные от его класса Model.

Класс Model

Все модели SQLAlchemy наследуются от декларативного базового класса. Это обозначается как db.Model в Flask-SQLAlchemy, который расширяет все модели. Это можно настроить путем создания подкласса по умолчанию и передачи пользовательского класса в model_class.

В следующем примере каждой модели присваивается целочисленный первичный ключ или внешний ключ для наследования объединенной таблицы.

Целочисленные первичные ключи для всего - не обязательно лучший дизайн базы данных (если только это не соответствует требованиям вашего проекта), это только пример

from flask_sqlalchemy import Model, SQLAlchemy
import sqlalchemy as sa
from sqlalchemy.ext.declarative import declared_attr, has_inherited_table

class IdModel(Model):
    @declared_attr
    def id(cls):
        for base in cls.__mro__[1:-1]:
            if getattr(base, '__table__', None) is not None:
                type = sa.ForeignKey(base.id)
                break
        else:
            type = sa.Integer

        return sa.Column(type, primary_key=True)

db = SQLAlchemy(model_class=IdModel)

class User(db.Model):
    name = db.Column(db.String)

class Employee(User):
    title = db.Column(db.String)

Смешивание моделей

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

from datetime import datetime

class TimestampMixin(object):
    created = db.Column(
        db.DateTime, nullable=False, default=datetime.utcnow)
    updated = db.Column(db.DateTime, onupdate=datetime.utcnow)

class Author(db.Model):
    ...

class Post(TimestampMixin, db.Model):
    ...

Query класс

Также возможно настроить то, что доступно для использования на специальном свойстве запроса моделей. Например, предоставив метод get_or:

from flask_sqlalchemy import BaseQuery, SQLAlchemy

class GetOrQuery(BaseQuery):
    def get_or(self, ident, default=None):
        return self.get(ident) or default

db = SQLAlchemy(query_class=GetOrQuery)

# получить пользователя по идентификатору или вернуть анонимный пользовательский экземпляр
user = User.query.get_or(user_id, anonymous_user)

И теперь все запросы, выполняемые из специального свойства запроса в моделях Flask-SQLAlchemy, могут использовать метод get_or как часть своих запросов. Все отношения, определенные с помощью db.relationship (но не sqlalchemy.orm.relationship()), также будут обеспечены этой функцией.

Также можно определить пользовательский класс запросов для отдельных отношений, указав в определении ключевое слово query_class. Это работает как с db.relationship, так и с sqlalchemy.relationship:

class MyModel(db.Model):
    cousin = db.relationship('OtherModel', query_class=GetOrQuery)

Если в отношении relationship определен класс запроса, он будет иметь приоритет над классом запроса, присоединенным к соответствующей модели.

Также можно определить конкретный класс запросов для отдельных моделей, переопределив атрибут класса query_class в модели:

class MyModel(db.Model):
    query_class = GetOrQuery

В этом случае метод get_or будет доступен только для запросов, исходящих из MyModel.query.

Metaclass модели

Метаклассы - это сложная тема, и вам, вероятно, не нужно настраивать их, чтобы достичь того, чего вы хотите. Здесь в основном описано, как отключить генерацию имен таблиц.

Metaclass модели отвечает за настройку внутренних компонентов SQLAlchemy при определении подклассов модели. Flask-SQLAlchemy добавляет некоторое дополнительное поведение через миксины; его метакласс по умолчанию DefaultMeta наследует их все.

  • BindMetaMixin: __bind_key__ извлекается из класса и применяется к таблице. См. Несколько баз данных с привязками.
  • NameMetaMixin: если модель не указывает __tablename__, но указывает первичный ключ, имя генерируется автоматически

Вы можете добавить свое поведение, определив свой собственный метакласс и создав декларативную базу самостоятельно. Не забудьте по-прежнему наследовать нужные миксины (или просто наследовать от метакласса по умолчанию).

Передача декларативного базового класса вместо простого базового класса модели, как показано выше, в base_class заставит Flask-SQLAlchemy использовать эту базу вместо ее создания с метаклассом по умолчанию.

from flask_sqlalchemy import SQLAlchemy
from flask_sqlalchemy.model import DefaultMeta, Model

class CustomMeta(DefaultMeta):
    def __init__(cls, name, bases, d):
        # пользовательская настройка класса может пойти здесь

        # обязательно вызовите super
        super(CustomMeta, cls).__init__(name, bases, d)

    # пользовательские методы только для классов могут быть здесь

db = SQLAlchemy(model_class=declarative_base(
    cls=Model, metaclass=CustomMeta, name='Model'))

Вы также можете передать любые другие аргументы, которые вы хотите объявить, чтобы описать базовый класс по мере необходимости.

Отключение генерации имени таблицы

Некоторые проекты предпочитают устанавливать __tablename__ каждой модели вручную, а не полагаться на обнаружение и генерацию Flask-SQLAlchemy. Генерацию имени таблицы можно отключить, определив пользовательский метакласс.

from flask_sqlalchemy.model import BindMetaMixin, Model
from sqlalchemy.ext.declarative import DeclarativeMeta, declarative_base

class NoNameMeta(BindMetaMixin, DeclarativeMeta):
    pass

db = SQLAlchemy(model_class=declarative_base(
    cls=Model, metaclass=NoNameMeta, name='Model'))

Это создает базу, которая все еще поддерживает функцию __bind_key__, но не генерирует имена таблиц.

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