From c80afa08c7aec23984e84bfb3ab5683c9c392115 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Wed, 17 Aug 2011 09:01:07 -0500 Subject: releng: refactor results overview page for performance Use some annotation stuff and trickeration to reduce the number of queries we need on the results overview page by quite a bit. Signed-off-by: Dan McGee --- releng/models.py | 26 -------------------------- releng/views.py | 49 +++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/releng/models.py b/releng/models.py index 3afef55e..a958288b 100644 --- a/releng/models.py +++ b/releng/models.py @@ -10,36 +10,10 @@ class IsoOption(models.Model): def __unicode__(self): return self.name - def get_test_result(self, success): - try: - return self.test_set.filter(success=success).select_related( - 'iso').latest('iso__id').iso - except Test.DoesNotExist: - return None - - def get_last_success(self): - return self.get_test_result(True) - - def get_last_failure(self): - return self.get_test_result(False) - class Meta: abstract = True class RollbackOption(IsoOption): - def get_rollback_test_result(self, success): - try: - return self.rollback_test_set.filter(success=success).select_related( - 'iso').latest('iso__id').iso - except Test.DoesNotExist: - return None - - def get_last_rollback_success(self): - return self.get_rollback_test_result(True) - - def get_last_rollback_failure(self): - return self.get_rollback_test_result(False) - class Meta: abstract = True diff --git a/releng/views.py b/releng/views.py index 796fc044..7f895a45 100644 --- a/releng/views.py +++ b/releng/views.py @@ -1,6 +1,6 @@ from django import forms from django.conf import settings -from django.db.models import Count +from django.db.models import Count, Max from django.http import Http404 from django.shortcuts import get_object_or_404, redirect from django.views.generic.simple import direct_to_template @@ -85,18 +85,49 @@ def calculate_option_overview(field_name): 'is_rollback': is_rollback, 'values': [] } + if not is_rollback: + successes = dict(model.objects.values_list('pk').filter( + test__success=True).annotate(latest=Max('test__iso__id'))) + failures = dict(model.objects.values_list('pk').filter( + test__success=False).annotate(latest=Max('test__iso__id'))) + else: + successes = dict(model.objects.values_list('pk').filter( + rollback_test_set__success=True).annotate( + latest=Max('rollback_test_set__iso__id'))) + failures = dict(model.objects.values_list('pk').filter( + rollback_test_set__success=False).annotate( + latest=Max('rollback_test_set__iso__id'))) + for value in model.objects.all(): - data = { 'value': value } - if is_rollback: - data['success'] = value.get_last_rollback_success() - data['failure'] = value.get_last_rollback_failure() - else: - data['success'] = value.get_last_success() - data['failure'] = value.get_last_failure() + data = { + 'value': value, + 'success': successes.get(value.pk), + 'failure': failures.get(value.pk), + } option['values'].append(data) return option +def options_fetch_iso(options): + '''Replaces the Iso PK with a full Iso model object in a list of options + used on the overview page. We do it this way to only have to query the Iso + table once rather than once per option.''' + # collect all necessary Iso PKs + all_pks = set() + for option in options: + all_pks.update(v['success'] for v in option['values']) + all_pks.update(v['failure'] for v in option['values']) + + all_pks.discard(None) + all_isos = Iso.objects.in_bulk(all_pks) + + for option in options: + for value in option['values']: + value['success'] = all_isos.get(value['success']) + value['failure'] = all_isos.get(value['failure']) + + return options + def test_results_overview(request): # data structure produced: # [ { option, name, is_rollback, values: [ { value, success, failure } ... ] } ... ] @@ -107,6 +138,8 @@ def test_results_overview(request): for field in fields: all_options.append(calculate_option_overview(field)) + all_options = options_fetch_iso(all_options) + context = { 'options': all_options, 'iso_url': settings.ISO_LIST_URL, -- cgit v1.2.3-55-g3dc8