Атрибут onupdate класса ForeignKey
Атрибут onupdate класса ForeignKey задает
SQL-действие, которое автоматически выполняется при
обновлении значения первичного ключа в родительской
таблице. Это поведение реализуется на уровне базы
данных через конструкцию ON UPDATE внешнего
ключа. Атрибут принимает строковые значения, такие
как CASCADE, SET NULL, SET DEFAULT,
RESTRICT и NO ACTION. Если атрибут не
указан, база данных применяет поведение по
умолчанию - обычно NO ACTION.
Синтаксис
ForeignKey('parent_table.column', onupdate='CASCADE')
Пример
Давайте создадим две связанные таблицы - users
и articles - и укажем для внешнего ключа
onupdate='CASCADE'. При обновлении id
пользователя значение внешнего ключа в статьях
обновится автоматически:
from sqlalchemy import create_engine, ForeignKey
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = 'users'
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
user_id: Mapped[int] = mapped_column(
ForeignKey('users.id', onupdate='CASCADE')
)
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
user = User(id=1, name='user')
session.add(user)
session.flush()
article = Article(id=1, title='article', user_id=1)
session.add(article)
session.commit()
user.id = 2
session.commit()
print(article.user_id)
Результат выполнения кода:
"2"
Пример
Давайте рассмотрим вариант с onupdate='SET NULL'.
При обновлении первичного ключа родителя внешний ключ
в дочерней таблице обнуляется:
from sqlalchemy import create_engine, ForeignKey
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = 'users'
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
user_id: Mapped[int] = mapped_column(
ForeignKey('users.id', onupdate='SET NULL'),
nullable=True
)
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
user = User(id=1, name='user')
session.add(user)
session.flush()
article = Article(id=1, title='article', user_id=1)
session.add(article)
session.commit()
user.id = 2
session.commit()
session.refresh(article)
print(article.user_id)
Результат выполнения кода:
"None"
Пример
Давайте посмотрим, какой SQL генерирует SQLAlchemy
при создании таблицы с onupdate='CASCADE':
from sqlalchemy import create_engine, ForeignKey
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy.schema import CreateTable
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = 'users'
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
user_id: Mapped[int] = mapped_column(
ForeignKey('users.id', onupdate='CASCADE')
)
engine = create_engine('sqlite:///:memory:')
print(CreateTable(Article.__table__).compile(engine))
Итоговый SQL запрос:
CREATE TABLE articles (
id INTEGER NOT NULL,
title VARCHAR NOT NULL,
user_id INTEGER NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY(user_id) REFERENCES users (id) ON UPDATE CASCADE
)
Смотрите также
-
класс
ForeignKey,
который представляет внешний ключ таблицы -
атрибут
ondelete,
который задает действие при удалении родителя -
атрибут
column,
который возвращает целевую колонку внешнего ключа -
метод
get_referent,
который возвращает родительский объект по внешнему ключу