Implemented queryset.group_by0
This commit is contained in:
parent
b88689864f
commit
800ee58d2d
|
@ -3,7 +3,7 @@ import inspect
|
||||||
from orchestra.apps.accounts.models import Account
|
from orchestra.apps.accounts.models import Account
|
||||||
|
|
||||||
|
|
||||||
def search_for_related(origin, max_depth=2):
|
def get_related_objects(origin, max_depth=2):
|
||||||
"""
|
"""
|
||||||
Introspects origin object and return the first related service object
|
Introspects origin object and return the first related service object
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,11 @@ from django.utils.functional import cached_property
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.core import caches, services
|
from orchestra.core import caches, services
|
||||||
|
from orchestra.models import queryset
|
||||||
from orchestra.utils.apps import autodiscover
|
from orchestra.utils.apps import autodiscover
|
||||||
|
|
||||||
from . import settings
|
from . import settings, helpers
|
||||||
from .handlers import ServiceHandler
|
from .handlers import ServiceHandler
|
||||||
from .helpers import search_for_related
|
|
||||||
|
|
||||||
|
|
||||||
autodiscover('handlers')
|
autodiscover('handlers')
|
||||||
|
@ -175,7 +175,7 @@ class Service(models.Model):
|
||||||
return services
|
return services
|
||||||
|
|
||||||
# FIXME some times caching is nasty, do we really have to? make get_plugin more efficient?
|
# FIXME some times caching is nasty, do we really have to? make get_plugin more efficient?
|
||||||
@cached_property
|
# @cached_property
|
||||||
def handler(self):
|
def handler(self):
|
||||||
""" Accessor of this service handler instance """
|
""" Accessor of this service handler instance """
|
||||||
if self.handler_type:
|
if self.handler_type:
|
||||||
|
@ -214,6 +214,19 @@ class Service(models.Model):
|
||||||
|
|
||||||
|
|
||||||
class OrderQuerySet(models.QuerySet):
|
class OrderQuerySet(models.QuerySet):
|
||||||
|
group_by = queryset.group_by
|
||||||
|
|
||||||
|
def bill(self, **options):
|
||||||
|
for account, services in self.group_by('account_id', 'service_id'):
|
||||||
|
bill_lines = []
|
||||||
|
for service, orders in services:
|
||||||
|
lines = helpers.create_bill_lines(service, orders, **options)
|
||||||
|
bill_lines.extend(lines)
|
||||||
|
helpers.create_bills(account, bill_lines)
|
||||||
|
|
||||||
|
def get_related(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def by_object(self, obj, **kwargs):
|
def by_object(self, obj, **kwargs):
|
||||||
ct = ContentType.objects.get_for_model(obj)
|
ct = ContentType.objects.get_for_model(obj)
|
||||||
return self.filter(object_id=obj.pk, content_type=ct, **kwargs)
|
return self.filter(object_id=obj.pk, content_type=ct, **kwargs)
|
||||||
|
@ -322,6 +335,6 @@ def update_orders(sender, **kwargs):
|
||||||
if instance.pk:
|
if instance.pk:
|
||||||
# post_save
|
# post_save
|
||||||
Order.update_orders(instance)
|
Order.update_orders(instance)
|
||||||
related = search_for_related(instance)
|
related = helpers.get_related_objects(instance)
|
||||||
if related:
|
if related:
|
||||||
Order.update_orders(related)
|
Order.update_orders(related)
|
||||||
|
|
|
@ -129,7 +129,7 @@ def resource_inline_factory(resources):
|
||||||
|
|
||||||
if not running_syncdb():
|
if not running_syncdb():
|
||||||
# not run during syncdb
|
# not run during syncdb
|
||||||
for resources in Resource.group_by_content_type():
|
for ct, resources in Resource.objects.group_by('content_type'):
|
||||||
inline = resource_inline_factory(resources)
|
inline = resource_inline_factory(resources)
|
||||||
model = resources[0].content_type.model_class()
|
model = ct.model_class()
|
||||||
insertattr(model, 'inlines', inline)
|
insertattr(model, 'inlines', inline)
|
||||||
|
|
|
@ -5,13 +5,17 @@ from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from djcelery.models import PeriodicTask, CrontabSchedule
|
from djcelery.models import PeriodicTask, CrontabSchedule
|
||||||
|
|
||||||
from orchestra.models.fields import MultiSelectField
|
from orchestra.models import queryset, fields
|
||||||
from orchestra.utils.functional import cached
|
from orchestra.utils.functional import cached
|
||||||
|
|
||||||
from . import helpers
|
from . import helpers
|
||||||
from .backends import ServiceMonitor
|
from .backends import ServiceMonitor
|
||||||
|
|
||||||
|
|
||||||
|
class ResourceQuerySet(models.QuerySet):
|
||||||
|
group_by = queryset.group_by
|
||||||
|
|
||||||
|
|
||||||
class Resource(models.Model):
|
class Resource(models.Model):
|
||||||
"""
|
"""
|
||||||
Defines a resource, a resource is basically an interpretation of data
|
Defines a resource, a resource is basically an interpretation of data
|
||||||
|
@ -58,11 +62,13 @@ class Resource(models.Model):
|
||||||
null=True, blank=True,
|
null=True, blank=True,
|
||||||
help_text=_("Crontab for periodic execution. "
|
help_text=_("Crontab for periodic execution. "
|
||||||
"Leave it empty to disable periodic monitoring"))
|
"Leave it empty to disable periodic monitoring"))
|
||||||
monitors = MultiSelectField(_("monitors"), max_length=256, blank=True,
|
monitors = fields.MultiSelectField(_("monitors"), max_length=256, blank=True,
|
||||||
choices=ServiceMonitor.get_plugin_choices(),
|
choices=ServiceMonitor.get_plugin_choices(),
|
||||||
help_text=_("Monitor backends used for monitoring this resource."))
|
help_text=_("Monitor backends used for monitoring this resource."))
|
||||||
is_active = models.BooleanField(_("is active"), default=True)
|
is_active = models.BooleanField(_("is active"), default=True)
|
||||||
|
|
||||||
|
objects = ResourceQuerySet.as_manager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = (
|
unique_together = (
|
||||||
('name', 'content_type'),
|
('name', 'content_type'),
|
||||||
|
@ -80,8 +86,12 @@ class Resource(models.Model):
|
||||||
task = PeriodicTask.objects.get(name=name)
|
task = PeriodicTask.objects.get(name=name)
|
||||||
except PeriodicTask.DoesNotExist:
|
except PeriodicTask.DoesNotExist:
|
||||||
if self.is_active:
|
if self.is_active:
|
||||||
PeriodicTask.objects.create(name=name, task='resources.Monitor',
|
PeriodicTask.objects.create(
|
||||||
args=[self.pk], crontab=self.crontab)
|
name=name,
|
||||||
|
task='resources.Monitor',
|
||||||
|
args=[self.pk],
|
||||||
|
crontab=self.crontab
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
if not self.is_active:
|
if not self.is_active:
|
||||||
task.delete()
|
task.delete()
|
||||||
|
@ -92,25 +102,11 @@ class Resource(models.Model):
|
||||||
def delete(self, *args, **kwargs):
|
def delete(self, *args, **kwargs):
|
||||||
super(Resource, self).delete(*args, **kwargs)
|
super(Resource, self).delete(*args, **kwargs)
|
||||||
name = 'monitor.%s' % str(self)
|
name = 'monitor.%s' % str(self)
|
||||||
PeriodicTask.objects.filter(name=name, task='resources.Monitor',
|
PeriodicTask.objects.filter(
|
||||||
args=[self.pk]).delete()
|
name=name,
|
||||||
|
task='resources.Monitor',
|
||||||
@classmethod
|
args=[self.pk]
|
||||||
def group_by_content_type(cls):
|
).delete()
|
||||||
prev = None
|
|
||||||
group = []
|
|
||||||
resources = cls.objects.filter(is_active=True).order_by('content_type')
|
|
||||||
for resource in resources:
|
|
||||||
ct = resource.content_type
|
|
||||||
if prev != ct:
|
|
||||||
if group:
|
|
||||||
yield group
|
|
||||||
group = [resource]
|
|
||||||
else:
|
|
||||||
group.append(resource)
|
|
||||||
prev = ct
|
|
||||||
if group:
|
|
||||||
yield group
|
|
||||||
|
|
||||||
|
|
||||||
class ResourceData(models.Model):
|
class ResourceData(models.Model):
|
||||||
|
@ -181,7 +177,7 @@ def create_resource_relation():
|
||||||
return self
|
return self
|
||||||
|
|
||||||
relation = GenericRelation('resources.ResourceData')
|
relation = GenericRelation('resources.ResourceData')
|
||||||
for resources in Resource.group_by_content_type():
|
for ct, resources in Resource.objects.group_by('content_type'):
|
||||||
model = resources[0].content_type.model_class()
|
model = ct.model_class()
|
||||||
model.add_to_class('resource_set', relation)
|
model.add_to_class('resource_set', relation)
|
||||||
model.resources = ResourceHandler()
|
model.resources = ResourceHandler()
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
def group_by(qset, *fields):
|
||||||
|
""" group_by iterator with support for multiple nested fields """
|
||||||
|
def nest(objects, ix):
|
||||||
|
objs = []
|
||||||
|
result = []
|
||||||
|
first = True
|
||||||
|
for obj in objects:
|
||||||
|
current = getattr(obj, fields[ix])
|
||||||
|
if first or current == previous:
|
||||||
|
objs.append(obj)
|
||||||
|
else:
|
||||||
|
if ix < len(fields)-1:
|
||||||
|
objs = nest(list(objs), ix+1)
|
||||||
|
result.append((previous, objs))
|
||||||
|
objs = [obj]
|
||||||
|
previous = current
|
||||||
|
first = False
|
||||||
|
if ix < len(fields)-1:
|
||||||
|
objs = nest(list(objs), ix+1)
|
||||||
|
result.append((current, objs))
|
||||||
|
return result
|
||||||
|
|
||||||
|
objs = []
|
||||||
|
first = True
|
||||||
|
for obj in qset.order_by(*fields):
|
||||||
|
current = getattr(obj, fields[0])
|
||||||
|
if first or current == previous:
|
||||||
|
objs.append(obj)
|
||||||
|
else:
|
||||||
|
if len(fields) > 1:
|
||||||
|
objs = nest(objs, 1)
|
||||||
|
yield previous, objs
|
||||||
|
objs = [obj]
|
||||||
|
previous = current
|
||||||
|
first = False
|
||||||
|
if len(fields) > 1:
|
||||||
|
objs = nest(objs, 1)
|
||||||
|
yield current, objs
|
Loading…
Reference in New Issue