Django多对多自关联场景下Record多级祖先收益计算实现问题
多级祖先分成逻辑实现方案
你的现有代码缺少两个核心逻辑:
- 没有对祖先节点做层级遍历,无法区分不同层级的分成比例
- 修改的是关联用户的收入属性,最后调用
self.items.save()不会生效,需要单独保存用户的userprofile对象
核心分成规则对应逻辑
首先计算单条新Record的可分配总金额:
per_item_total = self.cost / self.items.count()
每向上追溯一级,可分配金额就对半拆分,所以第k级祖先(k从1开始,直接父节点为第1级)的分成是 per_item_total / (2 ** k)。
修正后的完整calculate_income方法
from django.db import transaction 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() @transaction.atomic def calculate_income(self): if not self.items.exists(): return per_item_total = self.cost / self.items.count() for item in self.items.all(): # 兼容你原有逻辑:新Record作者为一级分成方,拿总金额的1/2 item.author.userprofile.income += per_item_total / 2 item.author.userprofile.save() # 层级遍历的当前节点列表,初始是直接祖先(第2级) current_level_nodes = list(item.extending.all()) # 第2级的分母是2^2=4,也就是你要找的delimiter初始值 current_divider = 4 # 记录已访问节点,避免有向图存在环导致死循环 visited = set() while current_level_nodes: next_level_nodes = [] for ancestor in current_level_nodes: if ancestor.id in visited: continue visited.add(ancestor.id) # 给当前层级的祖先加收入 ancestor.author.userprofile.income += per_item_total / current_divider ancestor.author.userprofile.save() # 收集上一级祖先,作为下一轮遍历的节点 next_level_nodes.extend(list(ancestor.extending.all())) # 下一级分母翻倍,匹配每级分剩余金额一半的规则 current_divider *= 2 # 剩余金额如果小于1分可以提前终止,避免无意义的计算 if per_item_total / current_divider < 0.01: break current_level_nodes = next_level_nodes
关键说明
- 代码里的
current_divider就是你要找的delimiter,每往上一级乘以2,刚好对半拆分剩余金额 - 加了事务原子性保证,要么所有收入都更新成功,要么都不更新,避免数据不一致
- 加了访问记录防止图有环导致死循环,同时加了最小金额阈值提前终止遍历,提升性能
- 每个userprofile修改后单独调用save方法,保证修改持久化
内容的提问来源于stack exchange,提问作者Pavel Shlepnev
相关产品推荐
相关产品推荐

