В Django есть встроенный функционал, подобный которому я описал в сабже в п.2.
Используется системой аутентификации Django.
Суть в следующем:
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericRelation
# создадим класс, хранящий множество записей, которые могут привязываться к разным моделями
class Accumulator(models.Model):
# Ссылка на встроенную модель, где фигурируют все модели всех зарегистрированных приложений
content_type = models.ForeignKey(ContentType, on_delete=models.PROTECT, editable=False, db_index=True)
# Ключ самого объекта, на который ссылаемся
object_id = models.UUIDField(editable=False, db_index=True)
# "Виртуальное" поле, в котором/через который взаимодействуем с объектом
content_object = GenericForeignKey('content_type', 'object_id')
# то, что собираем из всех моделей
sum = models.DecimalField(max_digits=12, decimal_places=2, verbose_name='Сумма')
class CashIn(models.Model)
# Вопрос религиозный. Останавливаться не буду :)
uuid = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4)
# Что регистрирует текущая модель
sum = models.DecimalField(max_digits=12, decimal_places=2, verbose_name='Сумма')
# Ссылка в объекте модели на записи
accumulator = GenericRelation(Accumulator)
# Переопределяем встроенные методы.
# Вопрос можно решить и через сигналы. Еще смотрю
def save(self, *args, **kwargs):
super(CashIn, self).save(*args, **kwargs)
self.accumulator.all().delete()
self.accumulator.create(sum=self.sum)
def delete(self, using=None, keep_parents=False):
self.accumulator.all().delete()
super(CashIn, self).delete(using=using, keep_parents=keep_parents)
# Аналогичен CashIn, но записывает в другую сторону сумму
class CashOut(models.Model)
uuid = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4)
sum = models.DecimalField(max_digits=12, decimal_places=2, verbose_name='Сумма')
accumulator = GenericRelation(Accumulator)
def save(self, *args, **kwargs):
super(CashOut, self).save(*args, **kwargs)
self.accumulator.all().delete()
self.accumulator.create(sum=-self.sum)
def delete(self, using=None, keep_parents=False):
self.accumulator.all().delete()
super(CashOut, self).delete(using=using, keep_parents=keep_parents)
После всего выше сказанного можно вытащить результат в "кассе" одной строкой, без анализа всех таблиц:
Accumulator.objects.all().aggregate(models.Sum('sum'))['sum__sum']