Каскадное удаление в SQLAlchemy

каскадное удаление в sqlalchemy

По данной теме не так много материалов в рунете. Вроде есть какие то статьи которые в общих чертах описывают сводки из официальной документации. Однако как всегда у меня по одним только примерам из документации не получилось настроить каскадное удаление.
Для тех кто не знает поясню о чем речь.

Каскадное удаление — это когда при удалении какого то объекта из базы, вместе с ним удаляются также связанные сущности. Приведу пример. В моем приложении при удалении пациента я также хочу удалить все связанные с ним документы и записи, так как хранить их базе не имеет смысла.

Итак начнем. Сначала приведу код моделей.

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)

Вот собственно и все, теперь когда мы удалим пациента у нас также удалятся все его записи. Однако я привел пример для одного внедшнего ключа, если у вас их для моделей много нужно для каждого настроить по аналогии.

Вам также может понравиться

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Яндекс.Метрика