我在更新calculated_special_order_items、calculated_floor_special_order_items、order_total、ship_total、confirm_total、real_total和calculated_total时遇到问题。当我通过正常保存的视图保存带有 Ship_special_order_items 的新实例时,calculated_special_order_items 会更新,并且所有总计都会正确更新,并且会正确显示在 django 管理站点中,但是当我尝试使用保存确认_special_order_items 来更新calculate_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()
我已经用模型内的代码尝试了两天的一切,即使使用保存后信号,即使使用 django admin 的自定义模型表单,我也没有解决方案,如果您遇到同样的问题并且成功解决,请帮助我。谢谢你。
在模型内部使用代码,甚至使用保存后信号,甚至使用 django admin 的自定义模型表单。
我相信这一点。所有这些方法都不会工作,因为 Django 填充或更新 ManyToManyField
[Django-doc] after 它已经保存了对象,所以当你的
def save(..)
运行时,或者你的post_save
signal[Django-doc],因为当时还没有数据,或者数据已经过时了。 您可以使用
m2m_changed
信号
[Django-doc]并在所有
ManyToManyField
上订阅此信号,但我也不喜欢这个:如果 ProductVariation
本身的数据例如,如果没有
Order
或
.product_variations
改变。
我认为当您需要批量执行此操作或对聚合进行过滤。在模型对象中保留“聚合”通常
不是一个好主意。主要问题是,大量场景可能会触发聚合过时,并且捕获所有这些情况几乎是不可能的。