Django post_save()信号实现

har*_*s h 61 python django django-signals django-models

我有一个关于django的问题.

我在这里有ManyToMany模型

class Product(models.Model):
     name = models.CharField(max_length=255)
     price = models.DecimalField(default=0.0, max_digits=9, decimal_places=2)
     stock = models.IntegerField(default=0)

     def  __unicode__(self):
         return self.name

class Cart(models.Model):
    customer = models.ForeignKey(Customer)
    products = models.ManyToManyField(Product, through='TransactionDetail')
    t_date = models.DateField(default=datetime.now())
    t_sum = models.FloatField(default=0.0)

    def __unicode__(self):
         return str(self.id)

class TransactionDetail(models.Model):
    product = models.ForeignKey(Product)
    cart = models.ForeignKey(Cart)
    amount = models.IntegerField(default=0)
Run Code Online (Sandbox Code Playgroud)

对于创建的1个购物车对象,我可以插入尽可能多的新TransactionDetail对象(产品和金额).我的问题是.我该如何实现触发器?我想要的是每当创建交易细节时,我希望产品库存的数量减去transactiondetail中的金额.

我读过有关post_save()但我不确定如何实现它.也许这样的事情

when:post_save(TransactionDetail,Cart)#Cart对象,其中TransactionDetail.cart = Cart.id

post_save(TransactionDetail, 
       Cart) #Cart object where TransactionDetail.cart= Cart.id
Cart.stock -= TransactionDetail.amount
Run Code Online (Sandbox Code Playgroud)

Ken*_*hen 149

如果你真的想用信号来达到这个目的,这里简要介绍一下,

from django.db.models.signals import post_save
from django.dispatch import receiver

class TransactionDetail(models.Model):
    product = models.ForeignKey(Product)

# method for updating
@receiver(post_save, sender=TransactionDetail, dispatch_uid="update_stock_count")
def update_stock(sender, instance, **kwargs):
    instance.product.stock -= instance.amount
    instance.product.save()
Run Code Online (Sandbox Code Playgroud)

  • 这个例子在django文档中是有争议的 (44认同)
  • 我得到"超出最大递归深度"错误,因为我在`@ receiver`函数中保存了实例本身.如何更新自我模型?我是否必须覆盖模型的`save()`方法? (5认同)
  • 什么是`dispatch_uid`? (5认同)
  • @Dipak 超出了最大递归深度,因为每次更新实例时都会触发 post_save,因此它在每次保存时都会调用自己,在递归深度值超过的状态下会出现异常。让我知道你是如何克服的 (2认同)
  • @VamsidharMuggulla而不是使用`signal`我重写了`save`方法的模型并使用`updated`函数更新了模型属性,这样它就不会再次触发保存. (2认同)

Mik*_*ael 16

我个人会覆盖TransactionDetail的save()方法,并在那里保存新的TransactionDetail然后运行

self.product.stock -= self.amount
self.product.save()
Run Code Online (Sandbox Code Playgroud)

  • 是,如果整个事务以原子模式运行 (2认同)

Gug*_*ata 7

如果你想避免获取maximum recursion depth exceeded,那么你应该在信号处理程序中保存之前断开信号.上面的例子(Kenny Shen的回答)将是:

from django.db.models.signals import post_save
from django.dispatch import receiver

class TransactionDetail(models.Model):
    # ... fields here

# method for updating
@receiver(post_save, sender=TransactionDetail, dispatch_uid="update_stock_count")
def update_stock(sender, instance, **kwargs):
 instance.product.stock -= instance.amount

 post_save.disconnect(update_stock, sender=TransactionDetail)
 instance.product.save()
 post_save.connect(update_stock, sender=TransactionDetail)
Run Code Online (Sandbox Code Playgroud)

这在模型的断开信号和django中的重新连接中有详细描述,并有一个更抽象和有用的例子.

另请参阅:django文档中的https://docs.djangoproject.com/en/2.0/topics/signals/#disconnecting-signals.

  • 为了让它工作,你需要在`disconnect`和`connect`方法中有`dispatch_uid`。返回值可帮助您处理潜在的错误。` is_disconnected = post_save.disconnect(update_stock, sender=TransactionDetail, dispatch_uid="update_stock_count") if is_diconnected: instance.product.save() is_reconnected = post_save.connect(update_stock, sender=TransactionDetail, dispatch_uid="update_stock_count") ` (2认同)

小智 6

如果你真的想在 django 中使用信号,请尝试以下操作:

#import inbuilt user model
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=User)
def create_profile(sender, **kwargs):
    # write you functionality
    pass
   
Run Code Online (Sandbox Code Playgroud)

然后default_app_config在init文件中添加

 default_app_config = "give your AppConfig path"
Run Code Online (Sandbox Code Playgroud)