我正在尝试根据OrderItem上的更新数量来更新订单总数。为此,我使用Django信号m2m通过post_add或post_remove操作进行更改。这是我的模型:
class Item(models.Model):
name = models.CharField(max_length=20, unique=True)
price = models.DecimalField(max_digits=8, decimal_places=2)
class Order(models.Model):
order_item = models.ManyToManyField('OrderItem')
total = models.DecimalField(max_digits=8, decimal_places=2, default=0.0)
class OrderItem(models.Model):
item = models.ForeignKey(Item, on_delete=models.PROTECT)
quantity = models.IntegerField()
total = models.DecimalField(max_digits=8, decimal_places=2, default=0.0)
OrderItem总更新信号
def pre_save_order_tem_receiver(sender, instance, *args, **kwargs):
"""Receiver for updating total of OrderItem"""
total = instance.item.price * instance.quantity
instance.total = total
pre_save.connect(pre_save_order_tem_receiver, sender=OrderItem)
m2m更改信号
def m2m_changed_order_item_receiver(sender, instance, action, *args, **kwargs):
"""Receiver for updating total of Order through OrderItem"""
if action in ["post_add", "post_remove"]:
order_items = instance.order_item.all()
total = 0
for order_item in order_items:
total += order_item.item.price * order_item.quantity
instance.total = total
instance.save()
m2m_changed.connect(m2m_changed_order_item_receiver, sender=Order.order_item.through)
Testcase:
def test_updating_order_item_quantity_in_order(self):
order_item1, order_item1_data = create_sample_order_item(
item=self.item1,
quantity=2,
data_only=False
)
order_item2, order_item2_data = create_sample_order_item(
item=self.item2,
quantity=2,
data_only=False
)
order, _ = create_sample_order(
order_items=[order_item1_data, order_item2_data],
data_only=False
)
order_items = order.order_item.all()
for order_item in order_items:
if order_item == order_item2:
order_item2.quantity = 10
order_item2.save()
order.save()
# update
order_item2_total = order_item2.item.price * 10
# works completly fine but i'm searching for alternative method using signal
# order.order_item.remove(order_item2)
# order.order_item.add(order_item2)
order.refresh_from_db()
order_item1.refresh_from_db()
order_item2.refresh_from_db()
# check weather OrderItem total is updated or not
self.assertEqual(order_item2.total, order_item2_total)
# fails here
self.assertEqual(order.total, order_item1.total + order_item2.total)
当我第一次从Order中删除OrderItem对象,更新并添加它时,它完全可以正常工作。即
# remove order_item
order.order_item.remove(order_item2)
# perform update
order_item.total = ......
# add back
order.order_item.add(order_item2)
除了使用信号删除,更新和添加以外,还有其他可靠的方法吗?
我认为您需要监听post_save
信号来执行此操作,因为您更新了单个对象。
[m2m_changed
的post_add
和post_remove
信号仅在模型关系中添加或删除了某些东西时调度。
这里是在OrderItem实例上使用post_save
的代码段。
def listen_order_item_change(sender, instance, **kwargs):
# get all orders
orders = instance.order_set.all()
for order in orders:
# update the each total for each order here
post_save.connect(listen_order_item_change, sender=OrderItem)
我认为这可以通过简单地触发post_save
信号来实现。
首先,您可以在OrderItem
模型内添加一个方法来更新总数,该方法稍后可以从post_save
信号接收器中调用。
这里是要在OrderItem
模型中定义的更新方法的代码段。
def update_total_price(self):
"""for updating the total_price of an ordered item"""
quantity = Decimal(self.quantity)
unit_price = self.item.price #for getting the unit price of the item
new_total_price = quantity * unit_price
self.total = new_total_price
self.save()
return new_total_price
最后是使用post_save信号及其接收者的代码段可以是]
def post_save_orderitem_total_receiver(sender,instance, created, *args, **kwargs):
if created:
instance.update_total_price()
post_save.connect(post_save_orderitem_total_receiver, sender=OrderItem)