""" Core abstract base models for the entire SaaS platform. All application models should inherit from BaseModel or SoftDeleteModel to ensure consistent UUID primary keys, timestamps, and soft-delete behavior. """ import uuid from typing import Optional from django.db import models from django.utils import timezone class BaseManager(models.Manager): """Default manager — returns all rows.""" pass class ActiveManager(models.Manager): """Manager that excludes soft-deleted rows.""" def get_queryset(self) -> models.QuerySet: return super().get_queryset().filter(deleted_at__isnull=True) class BaseModel(models.Model): """ Abstract base providing UUID primary key and timestamps. Every model in the project should inherit from this. """ id: models.UUIDField = models.UUIDField( primary_key=True, default=uuid.uuid4, editable=False, ) created_at: models.DateTimeField = models.DateTimeField( default=timezone.now, editable=False, ) updated_at: models.DateTimeField = models.DateTimeField(auto_now=True) class Meta: abstract = True ordering = ["-created_at"] def __str__(self) -> str: return str(self.id) class SoftDeleteModel(BaseModel): """ Abstract base adding soft-delete capability. Uses `deleted_at` timestamp instead of hard deletion. Access `objects` for active-only, `all_objects` for everything. """ deleted_at: models.DateTimeField = models.DateTimeField( null=True, blank=True, default=None, ) objects = ActiveManager() all_objects = BaseManager() class Meta(BaseModel.Meta): abstract = True def soft_delete(self) -> None: """Mark this record as deleted.""" self.deleted_at = timezone.now() self.save(update_fields=["deleted_at", "updated_at"]) def restore(self) -> None: """Restore a soft-deleted record.""" self.deleted_at = None self.save(update_fields=["deleted_at", "updated_at"]) @property def is_deleted(self) -> bool: return self.deleted_at is not None