Added filter by resource data on monitor data changelist
This commit is contained in:
parent
bea80f3edc
commit
5e4dead0c9
|
@ -75,8 +75,11 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
def display_billed_until(self, order):
|
def display_billed_until(self, order):
|
||||||
billed_until = order.billed_until
|
billed_until = order.billed_until
|
||||||
red = False
|
red = False
|
||||||
|
human = escape(naturaldate(billed_until))
|
||||||
if billed_until:
|
if billed_until:
|
||||||
if order.service.payment_style == order.service.POSTPAY:
|
if order.service.billing_period == order.service.NEVER:
|
||||||
|
human = _("Forever")
|
||||||
|
elif order.service.payment_style == order.service.POSTPAY:
|
||||||
boundary = order.service.handler.get_billing_point(order)
|
boundary = order.service.handler.get_billing_point(order)
|
||||||
if billed_until < boundary:
|
if billed_until < boundary:
|
||||||
red = True
|
red = True
|
||||||
|
@ -84,7 +87,7 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
red = True
|
red = True
|
||||||
color = 'style="color:red;"' if red else ''
|
color = 'style="color:red;"' if red else ''
|
||||||
return '<span title="{raw}" {color}>{human}</span>'.format(
|
return '<span title="{raw}" {color}>{human}</span>'.format(
|
||||||
raw=escape(str(billed_until)), color=color, human=escape(naturaldate(billed_until)),
|
raw=escape(str(billed_until)), color=color, human=human,
|
||||||
)
|
)
|
||||||
display_billed_until.short_description = _("billed until")
|
display_billed_until.short_description = _("billed until")
|
||||||
display_billed_until.allow_tags = True
|
display_billed_until.allow_tags = True
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from django.apps import apps
|
||||||
from django.contrib.admin import SimpleListFilter
|
from django.contrib.admin import SimpleListFilter
|
||||||
from django.db.models import Q, Prefetch, F
|
from django.db.models import Q, Prefetch, F
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from . import settings
|
||||||
from .models import MetricStorage
|
from .models import MetricStorage
|
||||||
|
|
||||||
|
|
||||||
|
@ -56,7 +58,12 @@ class BilledOrderListFilter(SimpleListFilter):
|
||||||
metric_queryset = queryset.exclude(service__metric='').exclude(billed_on__isnull=True)
|
metric_queryset = queryset.exclude(service__metric='').exclude(billed_on__isnull=True)
|
||||||
for order in metric_queryset.prefetch_related(prefetch_valid_metrics, prefetch_billed_metric):
|
for order in metric_queryset.prefetch_related(prefetch_valid_metrics, prefetch_billed_metric):
|
||||||
if len(order.billed_metric) != 1:
|
if len(order.billed_metric) != 1:
|
||||||
|
# corner case of prefetch_billed_metric: Does not always work with latests metrics
|
||||||
|
latest = order.metrics.latest()
|
||||||
|
if not latest:
|
||||||
raise ValueError("Data inconsistency #metrics %i != 1." % len(order.billed_metric))
|
raise ValueError("Data inconsistency #metrics %i != 1." % len(order.billed_metric))
|
||||||
|
billed_metric = latest.value
|
||||||
|
else:
|
||||||
billed_metric = order.billed_metric[0].value
|
billed_metric = order.billed_metric[0].value
|
||||||
for metric in order.valid_metrics:
|
for metric in order.valid_metrics:
|
||||||
if metric.created_on <= order.billed_on:
|
if metric.created_on <= order.billed_on:
|
||||||
|
@ -72,15 +79,18 @@ class BilledOrderListFilter(SimpleListFilter):
|
||||||
elif self.value() == 'no':
|
elif self.value() == 'no':
|
||||||
return queryset.exclude(billed_until__isnull=False, billed_until__gte=timezone.now())
|
return queryset.exclude(billed_until__isnull=False, billed_until__gte=timezone.now())
|
||||||
elif self.value() == 'pending':
|
elif self.value() == 'pending':
|
||||||
|
Service = apps.get_model(settings.ORDERS_SERVICE_MODEL)
|
||||||
return queryset.filter(
|
return queryset.filter(
|
||||||
Q(pk__in=self.get_pending_metric_pks(queryset)) | Q(
|
Q(pk__in=self.get_pending_metric_pks(queryset)) | Q(
|
||||||
Q(billed_until__isnull=True) | Q(billed_until__lt=timezone.now())
|
Q(billed_until__isnull=True) | Q(~Q(service__billing_period=Service.NEVER) &
|
||||||
|
Q(billed_until__lt=timezone.now()))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif self.value() == 'not_pending':
|
elif self.value() == 'not_pending':
|
||||||
return queryset.exclude(
|
return queryset.exclude(
|
||||||
Q(pk__in=self.get_pending_metric_pks(queryset)) | Q(
|
Q(pk__in=self.get_pending_metric_pks(queryset)) | Q(
|
||||||
Q(billed_until__isnull=True) | Q(billed_until__lt=timezone.now())
|
Q(billed_until__isnull=True) | Q(~Q(service__billing_period=Service.NEVER) &
|
||||||
|
Q(billed_until__lt=timezone.now()))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return queryset
|
return queryset
|
||||||
|
|
|
@ -12,7 +12,7 @@ def run_monitor(modeladmin, request, queryset):
|
||||||
for resource in queryset:
|
for resource in queryset:
|
||||||
rlogs = resource.monitor()
|
rlogs = resource.monitor()
|
||||||
if not async:
|
if not async:
|
||||||
logs = logs.union(set(map(str, rlogs)))
|
logs = logs.union(set([str(log.pk) for log in rlogs]))
|
||||||
modeladmin.log_change(request, resource, _("Run monitors"))
|
modeladmin.log_change(request, resource, _("Run monitors"))
|
||||||
if async:
|
if async:
|
||||||
num = len(queryset)
|
num = len(queryset)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from urllib.parse import parse_qs
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
from django.contrib import admin, messages
|
from django.contrib import admin, messages
|
||||||
from django.contrib.contenttypes.admin import GenericTabularInline
|
from django.contrib.contenttypes.admin import GenericTabularInline
|
||||||
|
@ -16,6 +18,7 @@ from orchestra.utils import db, sys
|
||||||
from orchestra.utils.functional import cached
|
from orchestra.utils.functional import cached
|
||||||
|
|
||||||
from .actions import run_monitor
|
from .actions import run_monitor
|
||||||
|
from .filters import ResourceDataListFilter
|
||||||
from .forms import ResourceForm
|
from .forms import ResourceForm
|
||||||
from .models import Resource, ResourceData, MonitorData
|
from .models import Resource, ResourceData, MonitorData
|
||||||
|
|
||||||
|
@ -147,25 +150,14 @@ class ResourceDataAdmin(ExtendedModelAdmin):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def used_monitordata_view(self, request, object_id):
|
def used_monitordata_view(self, request, object_id):
|
||||||
"""
|
|
||||||
Does the redirect on a separated view for performance reassons
|
|
||||||
(calculate this on a changelist is expensive)
|
|
||||||
"""
|
|
||||||
data = self.get_object(request, object_id)
|
|
||||||
ids = []
|
|
||||||
for dataset in data.get_monitor_datasets():
|
|
||||||
if isinstance(dataset, MonitorData):
|
|
||||||
ids.append(dataset.id)
|
|
||||||
else:
|
|
||||||
ids += dataset.values_list('id', flat=True)
|
|
||||||
url = reverse('admin:resources_monitordata_changelist')
|
url = reverse('admin:resources_monitordata_changelist')
|
||||||
url += '?id__in=%s' % ','.join(map(str, ids))
|
url += '?resource_data=%s' % object_id
|
||||||
return redirect(url)
|
return redirect(url)
|
||||||
|
|
||||||
|
|
||||||
class MonitorDataAdmin(ExtendedModelAdmin):
|
class MonitorDataAdmin(ExtendedModelAdmin):
|
||||||
list_display = ('id', 'monitor', 'display_created', 'value', 'content_object_link')
|
list_display = ('id', 'monitor', 'display_created', 'value', 'content_object_link')
|
||||||
list_filter = ('monitor',)
|
list_filter = ('monitor', ResourceDataListFilter)
|
||||||
add_fields = ('monitor', 'content_type', 'object_id', 'created_at', 'value')
|
add_fields = ('monitor', 'content_type', 'object_id', 'created_at', 'value')
|
||||||
fields = ('monitor', 'content_type', 'content_object_link', 'display_created', 'value')
|
fields = ('monitor', 'content_type', 'content_object_link', 'display_created', 'value')
|
||||||
change_readonly_fields = fields
|
change_readonly_fields = fields
|
||||||
|
@ -173,8 +165,23 @@ class MonitorDataAdmin(ExtendedModelAdmin):
|
||||||
content_object_link = admin_link('content_object')
|
content_object_link = admin_link('content_object')
|
||||||
display_created = admin_date('created_at', short_description=_("Created"))
|
display_created = admin_date('created_at', short_description=_("Created"))
|
||||||
|
|
||||||
|
def filter_used_monitordata(self, request, queryset):
|
||||||
|
query_string = parse_qs(request.META['QUERY_STRING'])
|
||||||
|
resource_data = query_string.get('resource_data')
|
||||||
|
if resource_data:
|
||||||
|
data = ResourceData.objects.get(pk=int(resource_data[0]))
|
||||||
|
ids = []
|
||||||
|
for dataset in data.get_monitor_datasets():
|
||||||
|
if isinstance(dataset, MonitorData):
|
||||||
|
ids.append(dataset.id)
|
||||||
|
else:
|
||||||
|
ids += dataset.values_list('id', flat=True)
|
||||||
|
return queryset.filter(id__in=ids)
|
||||||
|
return queryset
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
queryset = super(MonitorDataAdmin, self).get_queryset(request)
|
queryset = super(MonitorDataAdmin, self).get_queryset(request)
|
||||||
|
queryset = self.filter_used_monitordata(request, queryset)
|
||||||
return queryset.prefetch_related('content_object')
|
return queryset.prefetch_related('content_object')
|
||||||
|
|
||||||
|
|
||||||
|
|
17
orchestra/contrib/resources/filters.py
Normal file
17
orchestra/contrib/resources/filters.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
from django.contrib.admin import SimpleListFilter
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
class ResourceDataListFilter(SimpleListFilter):
|
||||||
|
""" Mock filter to avoid e=1 """
|
||||||
|
title = _("Resource data")
|
||||||
|
parameter_name = 'resource_data'
|
||||||
|
|
||||||
|
def lookups(self, request, model_admin):
|
||||||
|
return ()
|
||||||
|
|
||||||
|
def queryset(self, request, queryset):
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
def choices(self, cl):
|
||||||
|
return []
|
|
@ -225,8 +225,8 @@ class ResourceData(models.Model):
|
||||||
def monitor(self, async=False):
|
def monitor(self, async=False):
|
||||||
ids = (self.object_id,)
|
ids = (self.object_id,)
|
||||||
if async:
|
if async:
|
||||||
return tasks.monitor.delay(self.resource_id, ids=ids, async=async)
|
return tasks.monitor.delay(self.resource_id, ids=ids)
|
||||||
return tasks.monitor(self.resource_id, ids=ids, async=async)
|
return tasks.monitor(self.resource_id, ids=ids)
|
||||||
|
|
||||||
def get_monitor_datasets(self):
|
def get_monitor_datasets(self):
|
||||||
resource = self.resource
|
resource = self.resource
|
||||||
|
|
Loading…
Reference in a new issue