По данной теме не так много материалов в рунете. Вроде есть какие то статьи которые в общих чертах описывают сводки из официальной документации. Однако как всегда у меня по одним только примерам из документации не получилось настроить каскадное удаление.
Для тех кто не знает поясню о чем речь.
Каскадное удаление — это когда при удалении какого то объекта из базы, вместе с ним удаляются также связанные сущности. Приведу пример. В моем приложении при удалении пациента я также хочу удалить все связанные с ним документы и записи, так как хранить их базе не имеет смысла.
Итак начнем. Сначала приведу код моделей.
import uuid from sqlalchemy import Column, String, Integer, ForeignKey, DateTime, SmallInteger, Boolean from sqlalchemy.orm import relationship from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.sql import false from app.database.base import Base from app.models.mixins import TimestampMixin class Appointment(TimestampMixin, Base): """ Модель записи на прием """ __tablename__ = "apointments" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True) number = Column(Integer, index=True, nullable=False, comment="Номер документа") patient_id = Column(UUID(as_uuid=True), ForeignKey("patients.id", ondelete="CASCADE"), index=True, nullable=False, comment="ID пациента") doctor_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), index=True, nullable=False, comment="ID доктора") start = Column(DateTime(timezone=True), index=True, nullable=True, comment="Время начала приема") # ***** тут у вас будут свои поля clinic = relationship("Clinic", back_populates="appointments") doctor = relationship("User", back_populates="appointments") patient = relationship("Patient", back_populates="appointments") class Patient(TimestampMixin, Base): """ Модель пациентов """ __tablename__ = "patients" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True) first_name = Column(String, nullable=False, index=True, comment="Имя") last_name = Column(String, nullable=True, index=True, comment="Фамилия") patronymic = Column(String, nullable=True, index=True, comment="Отчество") # ***** тут у вас будут свои поля close_date = Column(DateTime, nullable=True, comment="Действителен до") clinic_id = Column(UUID(as_uuid=True), ForeignKey("clinics.id", ondelete=""), index=True) appointments = relationship( "Appointment", back_populates="patient", cascade="all, delete", passive_deletes=True) clinic = relationship("Clinic", back_populates="patients")
На что стоит обратить внимание? В первую очередь на то что мы для родительской модели Patient в отношении appointments меняем с
appointments = relationship("Appointment", back_populates="patient")
на
appointments = relationship( "Appointment", back_populates="patient", cascade="all, delete", passive_deletes=True)
то есть мы добавляем непосредственно признак самого каскада cascade=»all, delete», а также параметр passive_deletes=True который говорит о том что удаление будет происходить средстами СУБД.
А вот чтоб уже СУБД смогла удалить связанные записи нужно в дочерней модели, в моем случае это Appointment для ключа patient_id изменить.
Было так,
<br>patient_id = Column(UUID(<em>as_uuid</em>=True), ForeignKey("patients.id", <em>index</em>=True, <em>nullable</em>=False)
стало так
patient_id = Column(UUID(as_uuid=True), ForeignKey("patients.id", ondelete="CASCADE"), index=True, nullable=False)
Вот собственно и все, теперь когда мы удалим пациента у нас также удалятся все его записи. Однако я привел пример для одного внедшнего ключа, если у вас их для моделей много нужно для каждого настроить по аналогии.