Django多对多字段更新异常:calculating相关字段无法正确更新
Django多对多字段更新异常问题
问题描述
在更新以下字段时出现异常:
calculating_special_order_itemscalculating_floor_special_order_itemsorder_total、ship_total、confirm_total、real_total、calculating_total
具体表现:
- 视图创建新Order实例并关联
ship_special_order_items时,所有字段更新正常,calculating_special_order_items正确同步并在Django Admin中显示正常; - 当通过更新
confirm_special_order_items来同步更新calculating_special_order_items时,无法触发正确更新,目标字段未按预期同步数据。
相关模型代码
class Order(models.Model): STATUS_CHOICES = [("naruceno","naruceno"), ("poslato","poslato"), ("stiglo","stiglo")] ordering_facility = models.ForeignKey(Facility, on_delete=models.PROTECT, related_name='order_create_facility') dispatching_facility = models.ForeignKey(Facility, on_delete=models.PROTECT, related_name='order_dispatch_facility') order_timestamp = models.DateTimeField(auto_now_add=True) ship_timestamp = models.DateTimeField(blank=True, null=True) confirm_timestamp = models.DateTimeField(blank=True, null=True) real_timestamp = models.DateTimeField(blank=True, null=True) order_user = models.CharField(max_length=100, blank=True) ship_user = models.CharField(max_length=100, blank=True) confirm_user = models.CharField(max_length=100, blank=True) real_user = models.CharField(max_length=100, blank=True) status = models.CharField(max_length=20, choices=STATUS_CHOICES, default=STATUS_CHOICES[0][0]) product_variations = models.ManyToManyField(ProductVariation, through='OrderItem') order_total = models.DecimalField(max_digits=10, decimal_places=0, blank=True, null=True) ship_total = models.DecimalField(max_digits=10, decimal_places=0, blank=True, null=True) confirm_total = models.DecimalField(max_digits=10, decimal_places=0, blank=True, null=True) real_total = models.DecimalField(max_digits=10, decimal_places=0, blank=True, null=True) calculating_total = models.DecimalField(max_digits=10, decimal_places=0, blank=True, null=True) ship_special_order_items = models.ManyToManyField(SpecialOrderItem, blank=True, related_name='ship_special_order_items') ship_floor_special_order_items = models.ManyToManyField(FloorSpecialOrderItem, blank=True, related_name='ship_floor_special_order_items') confirm_special_order_items = models.ManyToManyField(SpecialOrderItem, blank=True, related_name='confirm_special_order_items') confirm_floor_special_order_items = models.ManyToManyField(FloorSpecialOrderItem, blank=True, related_name='confirm_floor_special_order_items') real_special_order_items = models.ManyToManyField(SpecialOrderItem, blank=True, related_name='real_special_order_items') real_floor_special_order_items = models.ManyToManyField(FloorSpecialOrderItem, blank=True, related_name='real_floor_special_order_items') calculating_special_order_items = models.ManyToManyField(SpecialOrderItem, blank=True, related_name='calculating_special_order_items') calculating_floor_special_order_items = models.ManyToManyField(FloorSpecialOrderItem, blank=True, related_name='calculating_floor_special_order_items') billed = models.BooleanField(default=False) def calculate_calculating_special_order_items(self): if self.real_special_order_items.exists(): return self.real_special_order_items.all() elif self.confirm_special_order_items.exists(): return self.confirm_special_order_items.all() elif self.ship_special_order_items.exists(): return self.ship_special_order_items.all() else: return [] def calculate_calculating_floor_special_order_items(self): if self.real_floor_special_order_items.exists(): return self.real_floor_special_order_items.all() elif self.confirm_floor_special_order_items.exists(): return self.confirm_floor_special_order_items.all() elif self.ship_floor_special_order_items.exists(): return self.ship_floor_special_order_items.all() else: return [] def update_total(self): self.calculating_special_order_items.set(self.calculate_calculating_special_order_items()) self.calculating_floor_special_order_items.set(self.calculate_calculating_floor_special_order_items()) ship_special_order_items_total = self.ship_special_order_items.aggregate(models.Sum('total'))['total__sum'] if self.ship_special_order_items.exists() else 0 ship_floor_special_order_items_total = self.ship_floor_special_order_items.aggregate(models.Sum('total'))['total__sum'] if self.ship_floor_special_order_items.exists() else 0 ship_specials_total = ship_special_order_items_total + ship_floor_special_order_items_total confirm_special_order_items_total = self.confirm_special_order_items.aggregate(models.Sum('total'))['total__sum'] if self.confirm_special_order_items.exists() else 0 confirm_floor_special_order_items_total = self.confirm_floor_special_order_items.aggregate(models.Sum('total'))['total__sum'] if self.confirm_floor_special_order_items.exists() else 0 confirm_specials_total = confirm_special_order_items_total + confirm_floor_special_order_items_total real_special_order_items_total = self.real_special_order_items.aggregate(models.Sum('total'))['total__sum'] if self.real_special_order_items.exists() else 0 real_floor_special_order_items_total = self.real_floor_special_order_items.aggregate(models.Sum('total'))['total__sum'] if self.real_floor_special_order_items.exists() else 0 real_specials_total = real_special_order_items_total + real_floor_special_order_items_total calculating_special_order_items_total = self.calculating_special_order_items.aggregate(models.Sum('total'))['total__sum'] if self.calculating_special_order_items.exists() else 0 calculating_floor_special_order_items_total = self.calculating_floor_special_order_items.aggregate(models.Sum('total'))['total__sum'] if self.calculating_floor_special_order_items.exists() else 0 calculating_specials_total = calculating_special_order_items_total + calculating_floor_special_order_items_total self.order_total = self.orderitem_set.aggregate(models.Sum('order_subtotal'))['order_subtotal__sum'] self.ship_total = self.orderitem_set.aggregate(models.Sum('ship_subtotal'))['ship_subtotal__sum'] + ship_specials_total if ship_specials_total > 0 and self.orderitem_set.aggregate(models.Sum('ship_subtotal'))['ship_subtotal__sum'] is not None else ship_specials_total if ship_specials_total>0 and self.orderitem_set.aggregate(models.Sum('ship_subtotal'))['ship_subtotal__sum'] is None else self.orderitem_set.aggregate(models.Sum('ship_subtotal'))['ship_subtotal__sum'] self.confirm_total = self.orderitem_set.aggregate(models.Sum('confirm_subtotal'))['confirm_subtotal__sum'] + confirm_specials_total if confirm_specials_total > 0 and self.orderitem_set.aggregate(models.Sum('confirm_subtotal'))['confirm_subtotal__sum'] is not None else confirm_specials_total if confirm_specials_total > 0 and self.orderitem_set.aggregate(models.Sum('confirm_subtotal'))['confirm_subtotal__sum'] is None else self.orderitem_set.aggregate(models.Sum('confirm_subtotal'))['confirm_subtotal__sum'] self.real_total = self.orderitem_set.aggregate(models.Sum('real_subtotal'))['real_subtotal__sum'] + real_specials_total if real_specials_total > 0 and self.orderitem_set.aggregate(models.Sum('real_subtotal'))['real_subtotal__sum'] is not None else real_specials_total if real_specials_total > 0 and self.orderitem_set.aggregate(models.Sum('real_subtotal'))['real_subtotal__sum'] is None else self.orderitem_set.aggregate(models.Sum('real_subtotal'))['real_subtotal__sum'] self.calculating_total = self.orderitem_set.aggregate(models.Sum('calculating_subtotal'))['calculating_subtotal__sum'] + calculating_specials_total if calculating_specials_total > 0 and self.orderitem_set.aggregate(models.Sum('calculating_subtotal'))['calculating_subtotal__sum'] is not None else calculating_specials_total if calculating_specials_total>0 and self.orderitem_set.aggregate(models.Sum('calculating_subtotal'))['calculating_subtotal__sum'] is None else self.orderitem_set.aggregate(models.Sum('calculating_subtotal'))['calculating_subtotal__sum'] def save(self, *args, **kwargs): super().save(*args, **kwargs) self.update_total() super().save(*args, **kwargs) def __str__(self): return f"{self.ordering_facility} {str(self.ship_timestamp)[0:19]} {self.calculating_total}" class OrderItem(models.Model): order = models.ForeignKey(Order, on_delete=models.CASCADE) product_variation = models.ForeignKey(ProductVariation, on_delete=models.PROTECT) order_quantity = models.PositiveIntegerField(blank=True, null=True) ship_quantity = models.PositiveIntegerField(blank=True, null=True) confirm_quantity = models.PositiveIntegerField(blank=True, null=True) real_quantity = models.PositiveIntegerField(blank=True, null=True) calculating_quantity = models.PositiveIntegerField(blank=True, null=True) order_subtotal = models.DecimalField(max_digits=10, decimal_places=0, blank=True, null=True) ship_subtotal = models.DecimalField(max_digits=10, decimal_places=0, blank=True, null=True) confirm_subtotal = models.DecimalField(max_digits=10, decimal_places=0, blank=True, null=True) real_subtotal = models.DecimalField(max_digits=10, decimal_places=0, blank=True, null=True) calculating_subtotal = models.DecimalField(max_digits=10, decimal_places=0, blank=True, null=True) @property def calculate_calculating_quantity(self): if self.real_quantity is not None: return self.real_quantity elif self.confirm_quantity is not None: return self.confirm_quantity elif self.ship_quantity is not None: return self.ship_quantity elif self.order_quantity is not None: return self.order_quantity else: return 0 @property def calculate_order_subtotal(self): return self.product_variation.price * self.order_quantity if self.order_quantity is not None else None @property def calculate_ship_subtotal(self): return self.product_variation.price * self.ship_quantity if self.ship_quantity is not None else None @property def calculate_confirm_subtotal(self): return self.product_variation.price * self.confirm_quantity if self.confirm_quantity is not None else None @property def calculate_real_subtotal(self): return self.product_variation.price * self.real_quantity if self.real_quantity is not None else None @property def calculate_calculating_subtotal(self): return self.product_variation.price * self.calculating_quantity if self.calculating_quantity is not None else None def save(self, *args, **kwargs): self.order_subtotal = self.calculate_order_subtotal self.ship_subtotal = self.calculate_ship_subtotal self.confirm_subtotal = self.calculate_confirm_subtotal self.real_subtotal = self.calculate_real_subtotal self.calculating_quantity = self.calculate_calculating_quantity self.calculating_subtotal = self.calculate_calculating_subtotal super().save(*args, **kwargs) self.order.update_total()
已尝试的解决方案
- 调整模型内部逻辑(如
save方法、update_total方法的执行顺序); - 使用Django post-save信号触发更新;
- 自定义Django Admin表单强制触发更新逻辑。
以上方法均未解决问题,耗时两天仍无进展,寻求可行的解决方案。
内容的提问来源于stack exchange,提问作者sine
相关产品推荐
相关产品推荐

