django - 更新 m2m 字段中的对象时如何使用 django 信号更新模型字段?
问题描述
我正在尝试在更新 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)
测试用例:
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 对象时,它工作得很好,更新并添加它。IE
# remove order_item
order.order_item.remove(order_item2)
# perform update
order_item.total = ......
# add back
order.order_item.add(order_item2)
除了使用信号删除,更新和添加之外,还有其他可靠的方法吗?
更新:
根据Muhammad Ihfazhillah提供的线索,我已经实现了部分工作代码,该代码只能在管理面板中工作。
def listen_order_item_change(sender, instance, **kwargs):
orders = instance.order_set.all()
for order in orders:
# get all order items
order_items = order.order_item.all()
total = 0
# find total for order
for order_item in order_items:
total += order_item.total
order.total = total
# save order
order.save()
# instance.save() -> causes RecursionError
post_save.connect(listen_order_item_change, sender=OrderItem)
解决方案
我认为您需要收听post_save
信号才能执行此操作,因为您更新了单个对象。
m2m_changed
'post_add
和信号仅在模型关系中添加或删除某些内容post_remove
时才发送。
post_save
这是在 OrderItem 实例上使用的片段。
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)
推荐阅读
- c# - Golang + C# 中 TLS 的配置问题
- web - 如何在 Folium 中完全自定义 LayerControl()?
- javascript - 自动化开发工作流程 - 连接 js 文件 [gulp]
- node.js - 如何使用 Mongodb 和 Node 优化 .find .count 查询?
- r - NA的R函数问题条件的长度> 1并且只使用第一个元素
- kotlin - 根据状态更改可组合
- python - pandas DataFrame:: 将记录值从一个数据帧的最后一行复制到另一个数据帧时显示错误
- vue.js - Vuex createPersistedState partial persist not working
- amazon-web-services - AWS SAM HttpApi - 添加 lambda auth 时出现内部服务器错误
- perl - 如何使用 perl 脚本删除重复的行