Многоуровневый доступ с помощью отношений ManyToMany в Django

У меня есть модели, объекты из которых можно представить в виде направленного графа:

from django.db import models
from django.contrib.auth.models import User

class Record(models.Model):
    name = models.CharField(max_length=100)
    description = models.CharField(max_length=500)
    content = models.TextField()
    sequels = models.ManyToManyField('self', blank=True, symmetrical=False, through='Extend', related_name='extending')
    author = models.ForeignKey(User, on_delete=models.CASCADE)

class Extend(models.Model):
    ancestor = models.ForeignKey(Record, on_delete=models.CASCADE, related_name='+')
    descendant = models.ForeignKey(Record, on_delete=models.CASCADE, related_name='+')

    class Meta:
        constraints = [
            models.UniqueConstraint(
                name="%(app_label)s_%(class)s_unique_relationships",
                fields=["ancestor", "descendant"],
            ),
            models.CheckConstraint(
                name="%(app_label)s_%(class)s_prevent_self_extend",
                check=~models.Q(ancestor=models.F("descendant")),
            ),
        ]

Когда создается новый экземпляр Record и он имеет связь с другим экземпляром через модель Extend, я хотел бы вычислить атрибут author.user.userprofile.income в экземпляре User. Проблема в том, что я не знаю, как вычислить этот атрибут для всех предков вновь созданного Record, который следует некоторому правилу: если вновь созданный Record стоит 50, предок первого уровня получает 25, а 25 переходит к другим предкам, постоянно делясь на 2.

enter image description here

Я могу написать формулу для предка первого уровня, но что для остальных?

# In case of some purchase:
class ExtendPurchase(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    items = models.ManyToManyField(Record)
    date = models.DateField(auto_now_add=True)
    cost = models.PositiveIntegerField()

    def calculate_income(self):
        for item in self.items.all():
            item.author.userprofile.income += self.cost / len(self.items.all()) / 2 # first-level; if one would like to extend more than one Record instance
            for ancestor in item.extending.all():
                ancestor.author.userprofile.income += self.cost / delimiter # I don't know what delimiter is to be written
        self.items.save()

Если я правильно понимаю, вы хотите рекурсивно просмотреть записи и разделить на 2 стоимость в каждом цикле.

Может ли это сработать для вас?

class ExtendPurchase(models.Model):
    # ...

    def calculate_income(self):

        def __income_from_record(record, cost):
            tmp_income = cost
            for rel in Extend.objects.select_related('descendant').filter(ancestor=record):
                tmp_income += __income_from_record(rel.descendant, cost/2)
            return tmp_income

        for record in self.items.all():
            income = __income_from_record(record, self.cost)
            record.ancestor.author.userprofile.income  = income
            record.ancestor.author.userprofile.save()
Вернуться на верх