Ссылочная целостность - как настроить SQLAlchemy? - PullRequest
1 голос
/ 14 сентября 2011

Может ли кто-нибудь помочь мне получить общую картину при настройке моделей SQLAlchemy, чтобы ссылочная целостность обеспечивалась на всех уровнях?

Исходя из идеи, что ссылочная целостность должна быть выражена и обеспечена БД, я создал схему (в настоящее время в Postgresql) со всеми необходимыми мне ограничениями, поэтому предоставление мне базы данных, которой я доверяю, обеспечит ссылочную целостность.

Затем я начинаю создавать приложение поверх этой БД, используя SQLAlchemy (0.7) в декларативном режиме.

Поискав и прочитав немного, я узнал, что могу настроить:

  • правила onupdate / ondelete для моих определений Column ().
  • опции каскада для моих определений отношений (),
    и кажется, что они работают на уровне сеанса в SQLAlchemy.
  • Параметры passive_deletes и passive_updates для моих определений отношений ().

И что все эти опции имеют значения по умолчанию.

Но я не уверен, сколько мне действительно нужно сделать с моими моделями SQLAlchemy, чтобы убедиться, что SQLAlchemy не синхронизируется с БД и ее ограничениями во время сеанса.

Чего именно я добиваюсь, если я настрою 'onupdate' и т. Д. В определениях Columns () в SQLAlchemy?

А для правил cascade и passive_delete / passive_update я могу настроить отношения (). Что мне здесь нужно и почему?

Или перефразируя мой вопрос: в какой степени SQLAlchemy будет знать об ограничениях, сконфигурированных в схеме БД, и в какой степени (и как) мне придется повторять их в моих моделях?

И что-нибудь еще, о чем я должен знать? :)

Ответы [ 2 ]

4 голосов
/ 30 сентября 2011

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

Ключевой темой SQLAlchemy является то, что она действительно выполняет только то, чтоВы говорите это.Поэтому, если вы попытаетесь сохранить объект SubWidget (), который в базе данных должен иметь ссылку на родительский Widget (), в тот момент, когда SQLAlchemy сбрасывает данные (т. Е. Выдает операторы INSERT), операция завершится неудачно.с нарушением ограничения, генерируемым базой данных, и транзакция откатывается.

Таким образом, предполагая, что FK для "subwidget" ссылается на "widget", ваше приложение должно убедиться, что данные находятся в правильной структуре.Есть два способа сделать это;один из них заключается в том, что вы вручную поддерживаете те столбцы, которые содержат ссылки на внешние ключи, и гарантируете, что они имеют соответствующее значение в точке INSERT или UPDATE.Другой способ заключается в том, что вы будете использовать relationship() для управления атрибутом внешнего ключа и вместо этого обеспечите, чтобы создание объекта SubWidget () сопровождалось операцией связывания его с родительским объектом Widget (), который выВы создали и / или приобрели отдельно.

Что касается каскадов, то отличная идея, хотя и не обязательная, иметь ON DELETE CASCADE для тех внешних ключей, где это применимо.Что касается SQLAlchemy, то при использовании relationship() вы обычно хотите дать ORM подсказку, что база данных будет каскадно удаляться через флаг passive_deletes (http://www.sqlalchemy.org/docs/orm/collections.html?highlight=passive_deletes#using-passive-deletes), однако обычно это повышение производительности;В противном случае SQLAlchemy гарантирует, что все объекты, представленные на зависимой стороне relationship(), загружаются в память и обрабатываются соответствующим образом, что означает либо установку атрибута внешнего ключа на NULL (по умолчанию), либо маркировку зависимого объекта для удаления (это происходит путем установки "cascade" в значение "all, delete-orphan", см. http://www.sqlalchemy.org/docs/orm/session.html#cascades).

ON UPDATE Каскад менее распространен, так как естественные первичные ключи не являются обычной практикой в ​​наши дни, так как они на самом деле неработают так же, как простые целочисленные первичные ключи, а также могут быть громоздкими другими способами. Однако SQLAlchemy также поддерживает их, и они, как правило, позаботятся о себе, так как SQLA предполагает, что по умолчанию каскады обновлений имеют место, когда происходит мутация PKсм. http://www.sqlalchemy.org/docs/orm/relationships.html#mutable-primary-keys-update-cascades для подробного описания этого.

Возможно, это все проще, если немного поэкспериментировать, основная идея в том, что SQLAlchemy испускает только тот SQL, о котором вы говоритехотя многие из его поведения SQLrs автоматизированы после предварительной настройки.relationship() должен быть настроен с подробной информацией о том, как вы хотите, чтобы он вел себя, когда данные сохраняются, изменяются или удаляются с учетом ограничений, присутствующих в базе данных.

1 голос
/ 30 сентября 2011

Итак, опираясь на ответ zzzeeks, и мое собственное изучение / мастеринг после моего первоначального вопроса ...

Чтобы активная SQLAlchemy предотвращала , что сессионный просмотр состояния БДможет отклоняться от того, что разрешает БД при очистке / фиксации, вы должны отразить все ограничения, найденные в схеме БД в ваших моделях SQLAlchemy.

И это делается с помощью определений столбцов в виде:

ForeignKey(..., onupdate='', ondelete='')
primary_key=True
unique=True

и т. Д. С возможным включением __table_args__, например:

__table_args__ = (
        ForeignKeyConstraint(['id'], ['remote_table.id']),
        UniqueConstraint('foo'),
        )

Для случаев, когда ограничение охватывает несколько столбцов.

Принимая во внимание:

relationship()

и связанные с ним аргументы, такие как:

cascade
cascade_backrefs
foreign_keys
passive_deletes
passive_updates

и т. Д., - (важная) удобная функция, позволяющая работать с вашими моделями с минимальными усилиями, насколько это возможно, но с максимальной эффективностью.не подразумевается, что предотвращает нарушение ссылочной целостности.

Функция Relationship () не может выразить все типичные ограничения в базе данных, в то время как Column () (и __table_args__) может.

С другой стороны, конфигурирование отношения () с некоторыми из перечисленных выше аргументов (или использование значений по умолчанию там, где это имеет смысл), позволит SQLAlchemy автоматически выполнять задачи, чтов конечном счете, можно сказать, что ссылочная целочисленность связана.И в противном случае это обычно должно быть выражено логикой в ​​окружающем коде.

Оптимальная конфигурация отношения () также в некоторых случаях позволит избежать ненужных операторов SQL, которые будут выдаваться SQLAlchemy.

Надеюсь, этосуммирование довольно точно ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...