Django post_save() 信号实现

问题描述 投票:0回答:5

我有一个关于 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)

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

我读过 post_save() 但我不确定如何实现它。 也许是这样的

时间:

post_save(TransactionDetail, 
       Cart) #Cart object where TransactionDetail.cart= Cart.id
Cart.stock -= TransactionDetail.amount
python django django-models django-signals
5个回答
199
投票

如果你真的想使用信号来实现这一点,这里简要介绍如何,

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()

22
投票

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

self.product.stock -= self.amount
self.product.save()

19
投票

如果你想避免得到

maximum recursion depth exceeded
,那么你应该 disconnect 信号,然后保存在信号处理程序中。上面的例子(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)

这在Disconnect signals for models and reconnect in django中有详细描述,有一个更抽象和有用的例子。

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


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
   

然后在初始化文件中添加

default_app_config

 default_app_config = "give your AppConfig path"

3
投票

事实上,文档字符串解释了

Signals
django.dispatch.Signal.connect

def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
    Connect receiver to sender for signal.

    Arguments:

        receiver
            A function or an instance method which is to receive signals.
            Receivers must be hashable objects.

            If weak is True, then receiver must be weak referenceable.

            Receivers must be able to accept keyword arguments.

            If a receiver is connected with a dispatch_uid argument, it
            will not be added if another receiver was already connected
            with that dispatch_uid.

        sender
            The sender to which the receiver should respond. Must either be
            a Python object, or None to receive events from any sender.

        weak
            Whether to use weak references to the receiver. By default, the
            module will attempt to use weak references to the receiver
            objects. If this parameter is false, then strong references will
            be used.

        dispatch_uid
            An identifier used to uniquely identify a particular instance of
            a receiver. This will usually be a string, though it may be
            anything hashable.
© www.soinside.com 2019 - 2024. All rights reserved.