80 lines
2.7 KiB
Python
80 lines
2.7 KiB
Python
from threading import local
|
|
|
|
from django.db.models.signals import pre_delete, pre_save
|
|
from django.dispatch import receiver
|
|
from django.http.response import HttpResponseServerError
|
|
|
|
from orchestra.core import services
|
|
from orchestra.utils.python import OrderedSet
|
|
|
|
from .models import Order
|
|
|
|
|
|
@receiver(pre_save, dispatch_uid='orders.ppre_save_collector')
|
|
def pre_save_collector(sender, *args, **kwargs):
|
|
if sender in services:
|
|
OrderMiddleware.collect(Order.SAVE, **kwargs)
|
|
|
|
@receiver(pre_delete, dispatch_uid='orders.pre_delete_collector')
|
|
def pre_delete_collector(sender, *args, **kwargs):
|
|
if sender in services:
|
|
OrderMiddleware.collect(Order.DELETE, **kwargs)
|
|
|
|
|
|
class OrderCandidate(object):
|
|
def __unicode__(self):
|
|
return "{}.{}()".format(str(self.instance), self.action)
|
|
|
|
def __init__(self, instance, action):
|
|
self.instance = instance
|
|
self.action = action
|
|
|
|
def __hash__(self):
|
|
""" set() """
|
|
opts = self.instance._meta
|
|
model = opts.app_label + opts.model_name
|
|
return hash(model + str(self.instance.pk) + self.action)
|
|
|
|
def __eq__(self, candidate):
|
|
""" set() """
|
|
return hash(self) == hash(candidate)
|
|
|
|
|
|
class OrderMiddleware(object):
|
|
"""
|
|
Stores all the operations derived from save and delete signals and executes them
|
|
at the end of the request/response cycle
|
|
"""
|
|
# Thread local is used because request object is not available on model signals
|
|
thread_locals = local()
|
|
|
|
@classmethod
|
|
def get_order_candidates(cls):
|
|
# Check if an error poped up before OrdersMiddleware.process_request()
|
|
if hasattr(cls.thread_locals, 'request'):
|
|
request = cls.thread_locals.request
|
|
if not hasattr(request, 'order_candidates'):
|
|
request.order_candidates = OrderedSet()
|
|
return request.order_candidates
|
|
return set()
|
|
|
|
@classmethod
|
|
def collect(cls, action, **kwargs):
|
|
""" Collects all pending operations derived from model signals """
|
|
request = getattr(cls.thread_locals, 'request', None)
|
|
if request is None:
|
|
return
|
|
order_candidates = cls.get_order_candidates()
|
|
instance = kwargs['instance']
|
|
order_candidates.add(OrderCandidate(instance, action))
|
|
|
|
def process_request(self, request):
|
|
""" Store request on a thread local variable """
|
|
type(self).thread_locals.request = request
|
|
|
|
def process_response(self, request, response):
|
|
if not isinstance(response, HttpResponseServerError):
|
|
candidates = type(self).get_order_candidates()
|
|
Order.process_candidates(candidates)
|
|
return response
|