Added filter by resource data on monitor data changelist

This commit is contained in:
Marc Aymerich 2015-06-16 11:34:46 +00:00
parent bea80f3edc
commit 5e4dead0c9
6 changed files with 59 additions and 22 deletions

View File

@ -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

View File

@ -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,8 +58,13 @@ 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:
raise ValueError("Data inconsistency #metrics %i != 1." % len(order.billed_metric)) # corner case of prefetch_billed_metric: Does not always work with latests metrics
billed_metric = order.billed_metric[0].value latest = order.metrics.latest()
if not latest:
raise ValueError("Data inconsistency #metrics %i != 1." % len(order.billed_metric))
billed_metric = latest.value
else:
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:
raise ValueError("This value should already be filtered on the prefetch query.") raise ValueError("This value should already be filtered on the prefetch query.")
@ -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

View File

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

View File

@ -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')

View 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 []

View File

@ -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