web-dev-qa-db-ja.com

Django post_save()シグナルの実装

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
58
haris h

本当に信号を使用してこれを達成したい場合、以下に簡単に説明します。

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
     instance.product.save()
141
Kenny Shen

個人的にはTransactionDetailのsave()メソッドをオーバーライドし、そこで新しいTransactionDetailを保存してから実行します

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

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)

これについては、 モデルの信号を切断し、Djangoで再接続する で詳細に説明し、より抽象的な有用な例を示します。

参照: https://docs.djangoproject.com/en/2.0/topics/signals/#disconnecting-signals Django docs 。

5

実際、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.
2
Zulu