Атрибут ondelete
Атрибут ondelete класса ForeignKey задает
SQL-операцию, которая выполняется базой данных при удалении
строки из родительской таблицы. Значением атрибута выступает
строка с одним из стандартных действий: CASCADE,
SET NULL, RESTRICT, NO ACTION или
SET DEFAULT. Атрибут передается в конструктор внешнего
ключа вторым параметром.
Синтаксис
ForeignKey(column, ondelete='CASCADE')
Пример
Давайте создадим две связанные модели и укажем для внешнего
ключа действие CASCADE, чтобы при удалении статьи
автоматически удалялись ее комментарии:
from sqlalchemy import ForeignKey, create_engine
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
comments: Mapped[list['Comment']] = relationship(
back_populates='article',
cascade='all, delete-orphan'
)
class Comment(Base):
__tablename__ = 'comments'
id: Mapped[int] = mapped_column(primary_key=True)
text: Mapped[str]
article_id: Mapped[int] = mapped_column(
ForeignKey('articles.id', ondelete='CASCADE')
)
article: Mapped['Article'] = relationship(back_populates='comments')
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
print('tables created')
Результат выполнения кода:
"tables created"
Пример
Давайте посмотрим, какой SQL генерируется для внешнего ключа
с атрибутом ondelete='SET NULL':
from sqlalchemy import ForeignKey, create_engine
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy.schema import CreateTable
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
class Comment(Base):
__tablename__ = 'comments'
id: Mapped[int] = mapped_column(primary_key=True)
text: Mapped[str]
article_id: Mapped[int] = mapped_column(
ForeignKey('articles.id', ondelete='SET NULL'),
nullable=True
)
engine = create_engine('sqlite:///:memory:')
print(CreateTable(Comment.__table__).compile(engine))
Итоговый SQL запрос:
CREATE TABLE comments (
id INTEGER NOT NULL,
text VARCHAR NOT NULL,
article_id INTEGER,
PRIMARY KEY (id),
FOREIGN KEY(article_id) REFERENCES articles (id) ON DELETE SET NULL
)
Пример
Давайте проверим действие CASCADE на практике: удалим
статью и убедимся, что связанные комментарии исчезли:
from sqlalchemy import ForeignKey, create_engine, select
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, Session
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
comments: Mapped[list['Comment']] = relationship(
back_populates='article',
cascade='all, delete-orphan'
)
class Comment(Base):
__tablename__ = 'comments'
id: Mapped[int] = mapped_column(primary_key=True)
text: Mapped[str]
article_id: Mapped[int] = mapped_column(
ForeignKey('articles.id', ondelete='CASCADE')
)
article: Mapped['Article'] = relationship(back_populates='comments')
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
article = Article(title='article')
article.comments.append(Comment(text='first'))
article.comments.append(Comment(text='second'))
session.add(article)
session.commit()
session.delete(article)
session.commit()
res = session.scalars(select(Comment)).all()
print(len(res))
Результат выполнения кода:
0
Смотрите также
-
класс
ForeignKey,
который представляет внешний ключ таблицы -
атрибут
onupdate,
который задает действие при обновлении родительской записи -
атрибут
column,
который возвращает целевую колонку внешнего ключа -
метод
references,
который проверяет ссылку на указанную колонку