Django post_save 没有触发但是 post_delete 在同一个 signals.py 文件中触发
Django post_save not firing but post_delete in same signals.py file does
我希望有人能向我解释为什么 post_save 不工作而 post_delete 看起来是,它们非常相似并且在同一个 signals.py 文件中:
Django 版本 3+
Python 版本 3+
models.py:
import uuid
from django.db import models
from django.db.models import Sum
from django.conf import settings
from products.models import Product
from shows.models import ShowsTickets
class Order(models.Model):
order_number = models.CharField(max_length=32, null=False, editable=False)
full_name = models.CharField(max_length=50, null=False, blank=False)
email = models.EmailField(max_length=254, null=False, blank=False)
phone_number = models.CharField(max_length=20, null=False, blank=False)
country = models.CharField(max_length=40, null=False, blank=False)
postcode = models.CharField(max_length=20, null=True, blank=True)
town_or_city = models.CharField(max_length=40, null=False, blank=False)
street_address1 = models.CharField(max_length=80, null=False, blank=False)
street_address2 = models.CharField(max_length=80, null=True, blank=True)
county = models.CharField(max_length=40, null=True, blank=True)
date = models.DateTimeField(auto_now_add=True)
delivery_cost = models.DecimalField(max_digits=6, decimal_places=2, null=False, default=0)
products_total = models.DecimalField(max_digits=6, decimal_places=2, null=True, default=0)
tickets_total = models.DecimalField(max_digits=6, decimal_places=2, null=True, default=0)
order_total = models.DecimalField(max_digits=6, decimal_places=2, null=False, default=0)
grand_total = models.DecimalField(max_digits=6, decimal_places=2, null=False, default=0)
def _generate_order_number(self):
"""Generate a random, unique order number using UUID"""
return uuid.uuid4().hex.upper()
def update_total(self):
"""Update grand total each time a line item is added,
accounting for delivery costs.
"""
self.products_total = (self.productlineitems.aggregate(
Sum('productlineitems_total'))['productlineitems_total__sum']) or 0
self.tickets_total = (self.ticketlineitems.aggregate(
Sum('ticketlineitems_total'))['ticketlineitems_total__sum']) or 0
self.order_total = self.products_total + self.tickets_total
self.delivery_cost = settings.STANDARD_DELIVERY_CHARGE
self.grand_total = self.order_total + self.delivery_cost
self.save()
def save(self, *args, **kwargs):
"""Override the original save method to set the order number
if it hasn't been set already.
"""
if not self.order_number:
self.order_number = self._generate_order_number()
super().save(*args, **kwargs)
def __str__(self):
return self.order_number
class OrderLineProductItem(models.Model):
order = models.ForeignKey(Order, null=False, blank=False, on_delete=models.CASCADE, related_name='productlineitems')
product = models.ForeignKey(Product, null=False, blank=False, on_delete=models.CASCADE)
quantity = models.IntegerField(null=False, blank=False, default=0)
productlineitems_total = models.DecimalField(max_digits=6, decimal_places=2, null=False, blank=False, editable=False)
def save(self, *args, **kwargs):
"""Override the original save method to set the lineproductitem total
and update the order total.
"""
self.productlineitems_total = self.product.price * self.quantity
super().save(*args, **kwargs)
def __str__(self):
return f'{self.product} on order {self.order.order_number}'
class OrderLineTicketItem(models.Model):
order = models.ForeignKey(Order, null=False, blank=False, on_delete=models.CASCADE, related_name='ticketlineitems')
ticket = models.ForeignKey(ShowsTickets, null=False, blank=False, on_delete=models.CASCADE)
quantity = models.IntegerField(null=False, blank=False, default=0)
ticketlineitems_total = models.DecimalField(max_digits=6, decimal_places=2, null=False, blank=False, editable=False)
def save(self, *args, **kwargs):
"""Override the original save method to set the lineticketitem total
and update the order total.
"""
self.ticketlineitems_total = self.ticket.price * self.quantity
super().save(*args, **kwargs)
def __str__(self):
return f'{self.ticket} on order {self.order.order_number}'
signals.py:
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from .models import OrderLineProductItem, OrderLineTicketItem
# not being called on update/create
@receiver(post_save, sender=OrderLineTicketItem)
@receiver(post_save, sender=OrderLineProductItem)
def update_on_save(sender, instance, created, **kwargs):
"""Update order total on lineproductitem and
lineticketitem update/create
"""
print('Hello, signals here!')
instance.order.update_total()
# works fine and, when called, updates everything accordingly
@receiver(post_delete, sender=OrderLineTicketItem)
@receiver(post_delete, sender=OrderLineProductItem)
def update_on_save(sender, instance, **kwargs):
"""Update order total on lineproductitem and
lineticketitem delete"""
print('Hello, signals here!')
instance.order.update_total()
我还添加了 import signals
到应用程序的配置 class' ready()
方法。
想法是让信号通过 update_total()
方法更新订单的 product_total、ticket_total 和 order_total 字段。
在使用任一项目创建实例或更新实例时,不计算总数。然而,当一个实例被删除时,一切都按预期工作并且 post_delete 信号触发(我用 print() 函数测试了它,如上所示。)
为什么 post_save 部分根本不触发(在创建或更新时)?
好的,我已经解决了这个问题。原来是我菜鸟的疏忽。
我的信号函数同名。将 @post_delete 函数更改为 update_on_delete() - 而不是 update_on_save() - 成功了。
我希望有人能向我解释为什么 post_save 不工作而 post_delete 看起来是,它们非常相似并且在同一个 signals.py 文件中:
Django 版本 3+ Python 版本 3+
models.py:
import uuid
from django.db import models
from django.db.models import Sum
from django.conf import settings
from products.models import Product
from shows.models import ShowsTickets
class Order(models.Model):
order_number = models.CharField(max_length=32, null=False, editable=False)
full_name = models.CharField(max_length=50, null=False, blank=False)
email = models.EmailField(max_length=254, null=False, blank=False)
phone_number = models.CharField(max_length=20, null=False, blank=False)
country = models.CharField(max_length=40, null=False, blank=False)
postcode = models.CharField(max_length=20, null=True, blank=True)
town_or_city = models.CharField(max_length=40, null=False, blank=False)
street_address1 = models.CharField(max_length=80, null=False, blank=False)
street_address2 = models.CharField(max_length=80, null=True, blank=True)
county = models.CharField(max_length=40, null=True, blank=True)
date = models.DateTimeField(auto_now_add=True)
delivery_cost = models.DecimalField(max_digits=6, decimal_places=2, null=False, default=0)
products_total = models.DecimalField(max_digits=6, decimal_places=2, null=True, default=0)
tickets_total = models.DecimalField(max_digits=6, decimal_places=2, null=True, default=0)
order_total = models.DecimalField(max_digits=6, decimal_places=2, null=False, default=0)
grand_total = models.DecimalField(max_digits=6, decimal_places=2, null=False, default=0)
def _generate_order_number(self):
"""Generate a random, unique order number using UUID"""
return uuid.uuid4().hex.upper()
def update_total(self):
"""Update grand total each time a line item is added,
accounting for delivery costs.
"""
self.products_total = (self.productlineitems.aggregate(
Sum('productlineitems_total'))['productlineitems_total__sum']) or 0
self.tickets_total = (self.ticketlineitems.aggregate(
Sum('ticketlineitems_total'))['ticketlineitems_total__sum']) or 0
self.order_total = self.products_total + self.tickets_total
self.delivery_cost = settings.STANDARD_DELIVERY_CHARGE
self.grand_total = self.order_total + self.delivery_cost
self.save()
def save(self, *args, **kwargs):
"""Override the original save method to set the order number
if it hasn't been set already.
"""
if not self.order_number:
self.order_number = self._generate_order_number()
super().save(*args, **kwargs)
def __str__(self):
return self.order_number
class OrderLineProductItem(models.Model):
order = models.ForeignKey(Order, null=False, blank=False, on_delete=models.CASCADE, related_name='productlineitems')
product = models.ForeignKey(Product, null=False, blank=False, on_delete=models.CASCADE)
quantity = models.IntegerField(null=False, blank=False, default=0)
productlineitems_total = models.DecimalField(max_digits=6, decimal_places=2, null=False, blank=False, editable=False)
def save(self, *args, **kwargs):
"""Override the original save method to set the lineproductitem total
and update the order total.
"""
self.productlineitems_total = self.product.price * self.quantity
super().save(*args, **kwargs)
def __str__(self):
return f'{self.product} on order {self.order.order_number}'
class OrderLineTicketItem(models.Model):
order = models.ForeignKey(Order, null=False, blank=False, on_delete=models.CASCADE, related_name='ticketlineitems')
ticket = models.ForeignKey(ShowsTickets, null=False, blank=False, on_delete=models.CASCADE)
quantity = models.IntegerField(null=False, blank=False, default=0)
ticketlineitems_total = models.DecimalField(max_digits=6, decimal_places=2, null=False, blank=False, editable=False)
def save(self, *args, **kwargs):
"""Override the original save method to set the lineticketitem total
and update the order total.
"""
self.ticketlineitems_total = self.ticket.price * self.quantity
super().save(*args, **kwargs)
def __str__(self):
return f'{self.ticket} on order {self.order.order_number}'
signals.py:
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from .models import OrderLineProductItem, OrderLineTicketItem
# not being called on update/create
@receiver(post_save, sender=OrderLineTicketItem)
@receiver(post_save, sender=OrderLineProductItem)
def update_on_save(sender, instance, created, **kwargs):
"""Update order total on lineproductitem and
lineticketitem update/create
"""
print('Hello, signals here!')
instance.order.update_total()
# works fine and, when called, updates everything accordingly
@receiver(post_delete, sender=OrderLineTicketItem)
@receiver(post_delete, sender=OrderLineProductItem)
def update_on_save(sender, instance, **kwargs):
"""Update order total on lineproductitem and
lineticketitem delete"""
print('Hello, signals here!')
instance.order.update_total()
我还添加了 import signals
到应用程序的配置 class' ready()
方法。
想法是让信号通过 update_total()
方法更新订单的 product_total、ticket_total 和 order_total 字段。
在使用任一项目创建实例或更新实例时,不计算总数。然而,当一个实例被删除时,一切都按预期工作并且 post_delete 信号触发(我用 print() 函数测试了它,如上所示。)
为什么 post_save 部分根本不触发(在创建或更新时)?
好的,我已经解决了这个问题。原来是我菜鸟的疏忽。
我的信号函数同名。将 @post_delete 函数更改为 update_on_delete() - 而不是 update_on_save() - 成功了。