94 votes

Implémentation du signal Django post_save()

J'ai une question à propos de django.

J'ai ici des modèles 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)

Pour un objet panier créé, je peux insérer autant de nouveaux objets TransactionDetail (le produit et le montant). Ma question est la suivante. Comment puis-je mettre en œuvre le déclencheur ? Ce que je veux, c'est qu'à chaque fois qu'un détail de transaction est créé, je veux que le montant du stock du produit soit soustrait du montant dans le détail de transaction.

J'ai lu des choses sur post_save() mais je ne suis pas sûr de savoir comment l'implémenter. Peut-être quelque chose comme ceci

quand :

post_save(TransactionDetail, 
       Cart) #Cart object where TransactionDetail.cart= Cart.id
Cart.stock -= TransactionDetail.amount

205voto

Pydroid Points 1166

Si vous voulez vraiment utiliser des signaux pour y parvenir, voici brièvement comment procéder,

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

22voto

Mikael Points 2268

Personnellement, je remplacerais la méthode save() du TransactionDetail et j'y enregistrerais le nouveau TransactionDetail, puis j'exécuterais la commande

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

19voto

Guglielmo Celata Points 189

Si vous voulez éviter d'être maximum recursion depth exceeded vous devez se déconnecter avant de l'enregistrer dans le gestionnaire de signal. L'exemple ci-dessus (réponse de Kenny Shen) serait alors le suivant :

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)

Cette procédure est décrite en détail dans le document Déconnexion des signaux pour les modèles et reconnexion dans django Le rapport de la Commission européenne sur les droits de l'homme et les libertés fondamentales, avec un exemple plus abstrait et plus utile, est un bon exemple.

Voir aussi https://docs.djangoproject.com/en/2.0/topics/signals/#disconnecting-signals dans la documentation de django.

6voto

a.patidar Points 371

Si vous voulez vraiment utiliser les signaux dans django, essayez ceci :

#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

puis ajouter default_app_config dans le fichier init

 default_app_config = "give your AppConfig path"

3voto

Zulu Points 1471

En fait, la docstring explique que la Signals est en 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.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X