Django post_save()信号实现

我有个关于姜戈的问题。

我这里有很多模特

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
131930 次浏览

Personally I would override the TransactionDetail's save() method and in there save the new TransactionDetail and then run

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

If you really want to use signals to achieve this, here's briefly how,

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

If you want to avoid getting maximum recursion depth exceeded, then you should disconnect signals, before saving within the signal handler. The example above (Kenny Shen's answer), would then be:

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)

This is described thoroughly in Disconnect signals for models and reconnect in django, with a more abstract and useful example.

Also see: https://docs.djangoproject.com/en/2.0/topics/signals/#disconnecting-signals in the django docs.

In fact, the docstrtring explains the Signals is in 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.

If you really want to use signals in django please try this:

#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
   

then add default_app_config in the init file

 default_app_config = "give your AppConfig path"