2017-10-06 4 views
1

J'essaie de développer un système de type enchères, où un client passe une commande, puis différents magasins peuvent offrir un prix pour cette commande.Utilisation de signaux django dans les classes de consommateurs de canaux

Une partie intéressante de ce système est que lorsque la commande est créée initialement, les magasins disponibles auront 60 secondes pour faire leur offre respective. Quand un premier magasin fait son offre, la «vente aux enchères» n'aura plus que les 20 secondes suivantes pour que les autres magasins fassent leur propre offre. S'ils font une autre offre, dans ce temps réduit, cette seconde est rafraîchie. Les offres peuvent continuer à être reçues tant qu'il y a suffisamment de temps, ce qui ne peut pas dépasser les 60 secondes initiales données. Outre ces exigences, je souhaite également mettre à jour le client lorsque de nouvelles offres arrivent en temps réel. En outre, je souhaite mettre à jour le client. Pour cela, j'utilise l'implémentation django-channels de WebSockets.

J'ai le fichier consumers.py suivant:

from channels.generic.websockets import WebsocketConsumer 
from threading import Timer 
from api.models import Order, OrderOffer 
from django.db.models.signals import post_save 
from django.dispatch import receiver 

class OrderConsumer(WebsocketConsumer): 

    def connect(self, message, **kwargs): 
     """ 
     Initialize objects here. 
     """ 
     order_id = int(kwargs['order_id']) 
     self.order = Order.objects.get(id=order_id) 
     self.timer = Timer(60, self.sendDone) 
     self.timer.start() 
     self.message.reply_channel.send({"accept": True}) 

    def sendDone(self): 
     self.send(text="Done") 

    # How do I bind self to onOffer? 
    @receiver(post_save, sender=OrderOffer) 
    def onOffer(self, sender, **kwargs): 
     self.send(text="Offer received!") 
     if (len(self.offers) == 0): 
      self.offerTimer = Timer(20, self.sendDone) 
      self.offers = [kwargs['instance'],] 
     else: 
      self.offerTimer = Timer(20, self.sendDone) 

     self.offers.append(kwargs['instance']) 


    def receive(self, text=None, bytes=None, **kwargs): 
     # Echo 
     self.send(text=text, bytes=bytes) 

    def disconnect(self, message, **kwargs): 
     """ 
     Perform necessary disconnect operations. 
     """ 
     pass 

j'ai pu avec succès à établir un canal de communication WebSocket entre mon client et le serveur. J'ai testé l'envoi de messages, et tout semble ok. Maintenant, je veux détecter la création de nouveaux OrderOffer, et envoyer une notification au client. Pour cela, j'ai besoin d'accéder à la variable self, pour utiliser self.send, ce qui est impossible, car le décorateur de signaux n'envoie pas ce paramètre. Je l'ai essayé de forcer en déclarant onOffer avec moi, mais je reçois l'erreur suivante:

TypeError: onOffer() missing 1 required positional argument: 'self'

Si je pouvais accéder en quelque sorte les arguments de mots clés, qui signale des ensembles, je pourrais peut-être faire quelque chose comme: context = self .

J'apprécierais n'importe quelle aide, ou même des solutions alternatives à mon problème original.

Répondre

0

Si vous voulez parler au consommateur de « l'extérieur » - dans ce cas, à partir d'un modèle méthode de sauvegarde - vous aurez besoin d'utiliser une couche de canal pour lui parler: http://channels.readthedocs.io/en/latest/topics/channel_layers.html

Essentiellement, vous ll faut:

  • Ajouter le consommateur à un groupe au démarrage (probablement basé sur son numéro de commande)
  • Envoyer un message au groupe chaque fois qu'il ya une nouvelle OrderOffer avec une coutume type - par exemple, {"type": "order.new_offer", "order_offer_id": 45}
  • Définir un gestionnaire sur la consommation qui gère ce - il correspond au nom du type, dans ce cas, il serait def order_new_offer(self, event):
  • Dans ce gestionnaire, vous pouvez alors utiliser self.send pour parler en bas de la prise (et interroger la base de données si vous avez besoin d'informations supplémentaires à envoyer au client que vous n'avez pas mis dans le message d'événement).

Vous pouvez voir une variante de ce dans le projet exemple multichat: https://github.com/andrewgodwin/channels-examples/tree/master/multichat