Soft delete

flarchitect can mark records as deleted without removing them from the database. This allows you to hide data from normal queries while retaining it for auditing or future restoration.

Configuration

Enable soft deletes and define how records are flagged:

class Config:
    API_SOFT_DELETE = True
    API_SOFT_DELETE_ATTRIBUTE = "deleted"
    API_SOFT_DELETE_VALUES = (False, True)

API_SOFT_DELETE_ATTRIBUTE names the column that stores the deleted flag. API_SOFT_DELETE_VALUES is a tuple where the first value represents an active record and the second marks it as deleted.

Example model

Add a boolean column to your base model so every table can inherit the flag:

from datetime import datetime
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import Boolean, DateTime
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column

class BaseModel(DeclarativeBase):
    created: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
    updated: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    deleted: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)

db = SQLAlchemy(model_class=BaseModel)

class Book(db.Model):
    __tablename__ = "books"
    id: Mapped[int] = mapped_column(primary_key=True)
    title: Mapped[str] = mapped_column()

Example queries

Soft deleted rows are hidden from normal requests:

GET /api/books        # returns rows where deleted=False

Include the include_deleted query parameter to return all rows:

GET /api/books?include_deleted=true

Issuing a DELETE request marks the record as deleted. To remove it permanently, supply cascade_delete=1:

DELETE /api/books/1             # sets deleted=True
DELETE /api/books/1?cascade_delete=1  # removes row from database