Декларирование Models¶
Вообще Flask-SQLAlchemy ведет себя как правильно сконфигурированная
описательная база из расширения declarative
. Мы
рекомендуем прочитать документацию SQLAlchemy для полного восприятия.
Однако, наиболее распространенные примеры отражены здесь.
Что нужно иметь ввиду:
- Базовый класс для всех ваших моделей называется db.Model. Он хранится в экземпляре SQLAlchemy который вы создаете. Смотрите Быстрый старт для дополнительной информации.
- Некоторые части требуемые в SQLAlchemy не являются обязательными в Flask-SQLAlchemy. Например имя таблицы устанавливается автоматически, если оно не было заданно. Оно образуется из названия класса с преобразованием имени в нижний регистр, так “CamelCase” преобразуется в “camel_case”. Чтобы определить имя таблицы, установите атрибут __tablename__.
Простой пример¶
Очень простой пример:
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True)
def __init__(self, username, email):
self.username = username
self.email = email
def __repr__(self):
return '<User %r>' % self.username
Использыйте Column
для определения столбца.
Имя столбца - это имя атрибута которому оно присвоенно. Если
вы хотите использовать другое имя в таблице, вы можете указать
необязательный первый аргумент, который является строкой определяющей
имя столбца. Первичные ключи отмечаются с помощью
primary_key=True
. Несколько ключей могут быть отмечены как
первичные ключи в этом случае они образуют составной первичный ключ.
Тип столбца является первый аргумент в Column
.
Вы можете указать их непосредственно или вызвать их в дальнейшем с
дополнительным определением (например указать длинну). Следующие
типы наиболее распространены:
Integer | Числовой |
String (size) | Числовой с указанием размера |
Text | Более длинный текс в юникоде |
DateTime | Дата и время выраженные как объект
Python datetime |
Float | Число с плавающей точкой |
Boolean | Логическое значение |
PickleType | Хранит pickled Python объект |
LargeBinary | Хранит большие произвольные бинарные данные |
Связь Один-ко-Многим¶
Связь Один-ко-Многим являются наиболее распространенными. Поскольку связи объявляются, прежде чем они установлены вы можете использовать строки для обозначения классов, которые еще не созданы (например, если Person определяет свзяь к Address, которая объявляется позднее в файле).
Связи записываются с помощью функции
relationship()
.
Однако внешний ключ должен быть объевлен отдельно с помощью
класса sqlalchemy.schema.ForeignKey
:
class Person(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50))
addresses = db.relationship('Address', backref='person',
lazy='dynamic')
class Address(db.Model):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(50))
person_id = db.Column(db.Integer, db.ForeignKey('person.id'))
Что же делает db.relationship()
? Эта функция возвращает новое
свойство, которое может сделать несколько вещей. В данном случае мы
сказали ей указывать на класс Address и загружать их несколько.
Откуда он знает, что будет возвращать более одного адреса?
Потому что SQLAlchemy угадывает полезные преднастройки из вашего
описания. Если вы хотели бы иметь свзяь один к одному можно
указать uselist=False
в relationship()
.
Итак что же изначают параметры backref и lazy? backref простой
способ объявить новое свойство для класса Address. Вы можете также
использовать my_address.person
чтобы обратиться к человеку из этого
адреса. lazy определяет, когда SQLAlchemy будет загружать данные
из базы данных:
'select'
(значение по умолчанию) означет что SQLAlchemy будет загружать данные по мере необходимости в один заход с использованием стандартного оператора выбора.'joined'
говорит SQLAlchemy загружать связи в том же запросе что и родительский используя оператор JOIN.'subquery'
работает как'joined'
, но SQLAlchemy использует подзапрос.'dynamic'
является особено полезным, если у вас есть много элементов. Вместо того чтобы загружать элементы SQLAlchemy будет возвращать объект запроса, который вы можете дополнительно уточнить перед загрузкой элементов. Как правило, это как раз то, в чем вы нуждаетесь, если ожидаете более чем несколько элементов для этих связей.
Как вам определить lazy статус для backrefs? Используйте функцию
backref()
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50))
addresses = db.relationship('Address',
backref=db.backref('person', lazy='joined'), lazy='dynamic')
Связь Многие-ко-Многим¶
Если вы хотите использовать связи много-ко-многим вам нужно будет определить вспомогательную таблицу, которая будет использоваться для связей. Для этой вспомогательной таблице строго рекмендуется не использовать model, а создать ее самостоятельно:
tags = db.Table('tags',
db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')),
db.Column('page_id', db.Integer, db.ForeignKey('page.id'))
)
class Page(db.Model):
id = db.Column(db.Integer, primary_key=True)
tags = db.relationship('Tag', secondary=tags,
backref=db.backref('pages', lazy='dynamic'))
class Tag(db.Model):
id = db.Column(db.Integer, primary_key=True)
Здесь мы задали Page.tags как список тэгов загружаемых в один заход, потому что мы не ожидаем большого количества тегов на одной странице. Список страниц на тэг (Tag.pages) однако является динамическим backref. Как уже упоминалось выше, это означает, что вы получите объект запроса обратно и можете использовать для выборки в нем (прим.пер. слабо понял последнюю фразу =().