.. _models: .. currentmodule:: flask_sqlalchemy Декларирование Models ===================== Вообще Flask-SQLAlchemy ведет себя как правильно сконфигурированная описательная база из расширения :mod:`~sqlalchemy.ext.declarative`. Мы рекомендуем прочитать документацию SQLAlchemy для полного восприятия. Однако, наиболее распространенные примеры отражены здесь. Что нужно иметь ввиду: - Базовый класс для всех ваших моделей называется `db.Model`. Он хранится в экземпляре SQLAlchemy который вы создаете. Смотрите :ref:`quickstart` для дополнительной информации. - Некоторые части требуемые в 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 '' % self.username Использыйте :class:`~sqlalchemy.Column` для определения столбца. Имя столбца - это имя атрибута которому оно присвоенно. Если вы хотите использовать другое имя в таблице, вы можете указать необязательный первый аргумент, который является строкой определяющей имя столбца. Первичные ключи отмечаются с помощью ``primary_key=True``. Несколько ключей могут быть отмечены как первичные ключи в этом случае они образуют составной первичный ключ. Тип столбца является первый аргумент в :class:`~sqlalchemy.Column`. Вы можете указать их непосредственно или вызвать их в дальнейшем с дополнительным определением (например указать длинну). Следующие типы наиболее распространены: =================== ===================================== `Integer` Числовой `String` (size) Числовой с указанием размера `Text` Более длинный текс в юникоде `DateTime` Дата и время выраженные как объект Python :mod:`~datetime.datetime` `Float` Число с плавающей точкой `Boolean` Логическое значение `PickleType` Хранит pickled Python объект `LargeBinary` Хранит большие произвольные бинарные данные =================== ===================================== Связь Один-ко-Многим ------------------------ Связь Один-ко-Многим являются наиболее распространенными. Поскольку связи объявляются, прежде чем они установлены вы можете использовать строки для обозначения классов, которые еще не созданы (например, если `Person` определяет свзяь к `Address`, которая объявляется позднее в файле). Связи записываются с помощью функции :func:`~sqlalchemy.orm.relationship`. Однако внешний ключ должен быть объевлен отдельно с помощью класса :class:`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`` в :func:`~sqlalchemy.orm.relationship`. Итак что же изначают параметры `backref` и `lazy`? `backref` простой способ объявить новое свойство для класса `Address`. Вы можете также использовать ``my_address.person`` чтобы обратиться к человеку из этого адреса. `lazy` определяет, когда SQLAlchemy будет загружать данные из базы данных: - ``'select'`` (значение по умолчанию) означет что SQLAlchemy будет загружать данные по мере необходимости в один заход с использованием стандартного оператора выбора. - ``'joined'`` говорит SQLAlchemy загружать связи в том же запросе что и родительский используя оператор `JOIN`. - ``'subquery'`` работает как ``'joined'``, но SQLAlchemy использует подзапрос. - ``'dynamic'`` является особено полезным, если у вас есть много элементов. Вместо того чтобы загружать элементы SQLAlchemy будет возвращать объект запроса, который вы можете дополнительно уточнить перед загрузкой элементов. Как правило, это как раз то, в чем вы нуждаетесь, если ожидаете более чем несколько элементов для этих связей. Как вам определить lazy статус для backrefs? Используйте функцию :func:`~sqlalchemy.orm.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. Как уже упоминалось выше, это означает, что вы получите объект запроса обратно и можете использовать для выборки в нем (прим.пер. слабо понял последнюю фразу =(). `Оригинал этой страницы `_