mirror of
https://github.com/Southampton-RSG/breccia-mapper.git
synced 2026-03-03 03:17:07 +00:00
perf: prefetch for serializers on network view
Reduces request time by more than 50%
This commit is contained in:
@@ -6,7 +6,7 @@ import logging
|
||||
import typing
|
||||
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.db.models import Q
|
||||
from django.db.models import Q, QuerySet
|
||||
from django.forms import ValidationError
|
||||
from django.utils import timezone
|
||||
from django.views.generic import TemplateView
|
||||
@@ -16,34 +16,47 @@ from people import forms, models, serializers
|
||||
logger = logging.getLogger(__name__) # pylint: disable=invalid-name
|
||||
|
||||
|
||||
def filter_by_form_answers(model: typing.Type, answerset_model: typing.Type, relationship_key: str):
|
||||
def filter_by_form_answers(queryset: QuerySet, answerset_queryset: QuerySet, relationship_key: str):
|
||||
"""Build a filter to select based on form responses."""
|
||||
def inner(form, at_date):
|
||||
answerset_set = answerset_model.objects.filter(
|
||||
def inner(form):
|
||||
# Filter on timestamp__date doesn't seem to work on MySQL
|
||||
# To compare datetimes we need at_date to be midnight at
|
||||
# the *end* of the day in question - so add one day
|
||||
|
||||
at_date = form.cleaned_data['date']
|
||||
if not at_date:
|
||||
at_date = timezone.now().date()
|
||||
at_date += timezone.timedelta(days=1)
|
||||
|
||||
# Filter to answersets valid at required time
|
||||
answerset_set = answerset_queryset.prefetch_related('question_answers').filter(
|
||||
Q(replaced_timestamp__gte=at_date)
|
||||
| Q(replaced_timestamp__isnull=True),
|
||||
timestamp__lte=at_date
|
||||
)
|
||||
|
||||
# Filter answers to relationship questions
|
||||
# Filter to answersets containing required answers
|
||||
for field, values in form.cleaned_data.items():
|
||||
if field.startswith(f'{form.question_prefix}question_') and values:
|
||||
answerset_set = answerset_set.filter(question_answers__in=values)
|
||||
|
||||
return model.objects.filter(pk__in=answerset_set.values_list(relationship_key, flat=True))
|
||||
return queryset.filter(pk__in=answerset_set.values_list(relationship_key, flat=True))
|
||||
|
||||
return inner
|
||||
|
||||
|
||||
filter_relationships = filter_by_form_answers(
|
||||
models.Relationship, models.RelationshipAnswerSet, 'relationship'
|
||||
models.Relationship.objects.prefetch_related('source', 'target'),
|
||||
models.RelationshipAnswerSet.objects, 'relationship'
|
||||
)
|
||||
|
||||
filter_organisations = filter_by_form_answers(
|
||||
models.Organisation, models.OrganisationAnswerSet, 'organisation'
|
||||
models.Organisation.objects, models.OrganisationAnswerSet.objects, 'organisation'
|
||||
)
|
||||
|
||||
filter_people = filter_by_form_answers(models.Person, models.PersonAnswerSet, 'person')
|
||||
filter_people = filter_by_form_answers(
|
||||
models.Person.objects, models.PersonAnswerSet.objects, 'person'
|
||||
)
|
||||
|
||||
|
||||
class NetworkView(LoginRequiredMixin, TemplateView):
|
||||
@@ -92,39 +105,21 @@ class NetworkView(LoginRequiredMixin, TemplateView):
|
||||
if not all(map(lambda f: f.is_valid(), all_forms.values())):
|
||||
return context
|
||||
|
||||
# Filter on timestamp__date doesn't seem to work on MySQL
|
||||
# To compare datetimes we need at_date to be midnight at
|
||||
# the *end* of the day in question - so add one day to each
|
||||
|
||||
relationship_at_date = all_forms['relationship'].cleaned_data['date']
|
||||
if not relationship_at_date:
|
||||
relationship_at_date = timezone.now().date()
|
||||
relationship_at_date += timezone.timedelta(days=1)
|
||||
|
||||
person_at_date = all_forms['person'].cleaned_data['date']
|
||||
if not person_at_date:
|
||||
person_at_date = timezone.now().date()
|
||||
person_at_date += timezone.timedelta(days=1)
|
||||
|
||||
organisation_at_date = all_forms['organisation'].cleaned_data['date']
|
||||
if not organisation_at_date:
|
||||
organisation_at_date = timezone.now().date()
|
||||
organisation_at_date += timezone.timedelta(days=1)
|
||||
|
||||
context['person_set'] = serializers.PersonSerializer(
|
||||
filter_people(all_forms['person'], person_at_date), many=True
|
||||
filter_people(all_forms['person']), many=True
|
||||
).data
|
||||
|
||||
context['organisation_set'] = serializers.OrganisationSerializer(
|
||||
filter_organisations(all_forms['organisation'], organisation_at_date), many=True
|
||||
filter_organisations(all_forms['organisation']), many=True
|
||||
).data
|
||||
|
||||
context['relationship_set'] = serializers.RelationshipSerializer(
|
||||
filter_relationships(all_forms['relationship'], relationship_at_date), many=True
|
||||
filter_relationships(all_forms['relationship']), many=True
|
||||
).data
|
||||
|
||||
context['organisation_relationship_set'] = serializers.OrganisationRelationshipSerializer(
|
||||
models.OrganisationRelationship.objects.all(), many=True
|
||||
models.OrganisationRelationship.objects.prefetch_related('source', 'target').all(),
|
||||
many=True
|
||||
).data
|
||||
|
||||
for person in models.Person.objects.all():
|
||||
|
||||
Reference in New Issue
Block a user