Skip to content

Commit 02cda36

Browse files
authored
Merge pull request #575 from HDRUK/merge_test_to_prod_2.0.10
Merge test to prod 2.0.10
2 parents f124ec6 + 9ee6b5c commit 02cda36

2 files changed

Lines changed: 72 additions & 19 deletions

File tree

api/mapping/services_rules.py

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from datetime import datetime
55

66
from django.contrib import messages
7+
from django.contrib.contenttypes.models import ContentType
78
from data.models import Concept, ConceptRelationship, ConceptAncestor
89

910
from mapping.models import ScanReportTable, ScanReportField, ScanReportValue
@@ -445,9 +446,6 @@ def get_mapping_rules_list(structural_mapping_rules):
445446
page and processed to build a json
446447
"""
447448

448-
# Queryset -> list, makes the calls to the db to get the rules
449-
structural_mapping_rules = list(structural_mapping_rules)
450-
451449
# get all scan_report_concepts that are used
452450
# get the ids first so we can make a batch call
453451
scan_report_concepts = list(
@@ -457,11 +455,12 @@ def get_mapping_rules_list(structural_mapping_rules):
457455
nmapped_concepts = len(scan_report_concepts)
458456

459457
# make the batch call
460-
scan_report_concepts = {
458+
scan_report_concepts_id_to_obj_map = {
461459
x.id: x
462460
for x in list(ScanReportConcept.objects.filter(pk__in=scan_report_concepts))
463461
}
464-
ntotal_concepts = len(scan_report_concepts.values())
462+
463+
ntotal_concepts = len(scan_report_concepts_id_to_obj_map.values())
465464

466465
if nmapped_concepts != ntotal_concepts:
467466
print(
@@ -470,15 +469,22 @@ def get_mapping_rules_list(structural_mapping_rules):
470469
)
471470

472471
# get all the ids for all ScanReportValues that are used (have been mapped with a concept)
473-
scan_report_values = [
472+
scanreportvalue_content_type = ContentType.objects.get_for_model(ScanReportValue)
473+
scan_report_values_with_scan_report_concepts = [
474474
obj.object_id
475-
for obj in scan_report_concepts.values()
476-
if obj.content_type.model_class() is ScanReportValue
475+
for obj in ScanReportConcept.objects.filter(
476+
pk__in=scan_report_concepts_id_to_obj_map,
477+
content_type=scanreportvalue_content_type,
478+
)
477479
]
478480
# make a batch call to the ORM again..
479-
scan_report_values = {
481+
scan_report_values_id_to_value_map = {
480482
obj.id: obj.value
481-
for obj in list(ScanReportValue.objects.filter(pk__in=scan_report_values))
483+
for obj in list(
484+
ScanReportValue.objects.filter(
485+
pk__in=scan_report_values_with_scan_report_concepts
486+
)
487+
)
482488
}
483489

484490
# get all destination field ids
@@ -506,10 +512,41 @@ def get_mapping_rules_list(structural_mapping_rules):
506512
for obj in list(ScanReportTable.objects.filter(pk__in=source_tables))
507513
}
508514

509-
# now looop over the rules to actually create the list version of the rules
515+
# Using select_related() means we can chain together querysets into one database
516+
# query rather than using multiple
517+
structural_mapping_rules_sr_concepts = structural_mapping_rules.select_related(
518+
"concept"
519+
)
520+
# Generate rule.id to SRConcept.id map for all SRConcepts related to these rules.
521+
rule_to_srconcept_id_map = {
522+
obj.id: obj.concept.id for obj in structural_mapping_rules_sr_concepts
523+
}
524+
525+
structural_mapping_rules_sr_concepts_concepts = (
526+
structural_mapping_rules.select_related("concept__concept")
527+
)
528+
# Generate MappingRule.id to Concept.id map for all Concepts related to SRConcepts
529+
# related to these MappingRules.
530+
rule_id_to_concept_name_map = {
531+
obj.id: obj.concept.concept.concept_name
532+
for obj in structural_mapping_rules_sr_concepts_concepts
533+
}
534+
535+
# Make a single query to get all ScanReportConcepts associated to
536+
# ScanReportValues. This means we avoid what would be more understandable,
537+
# but extremely slow, code to check whether each object is associated to a
538+
# ScanReportValue.
539+
scan_report_concepts_with_values = [
540+
obj.id
541+
for obj in ScanReportConcept.objects.filter(
542+
pk__in=scan_report_concepts_id_to_obj_map,
543+
content_type=scanreportvalue_content_type,
544+
)
545+
]
546+
547+
# now loop over the rules to actually create the list version of the rules
510548
rules = []
511549
for rule in structural_mapping_rules:
512-
513550
# get the fields/tables from the loop up lists
514551
# the speed up comes from here as we dont need to keep hitting the DB to get this data
515552
# we've already cached it in these dictionaries by making a batch call
@@ -520,28 +557,35 @@ def get_mapping_rules_list(structural_mapping_rules):
520557
source_table = source_tables[source_field.scan_report_table_id]
521558

522559
# get the concepts again
523-
scan_report_concept_id = rule.concept_id
524-
if rule.concept_id not in scan_report_concepts:
560+
rule_scan_report_concept_id = rule_to_srconcept_id_map[rule.id]
561+
562+
if rule.concept_id not in scan_report_concepts_id_to_obj_map:
525563
print(f"WARNING!! scan_report_concept {rule.concept_id} no longer exists")
526564
continue
527-
scan_report_concept = scan_report_concepts[rule.concept_id]
565+
566+
scan_report_concept = scan_report_concepts_id_to_obj_map[rule.concept_id]
567+
528568
concept_id = scan_report_concept.concept_id
529-
concept_name = scan_report_concept.concept.concept_name
569+
570+
concept_name = rule_id_to_concept_name_map[rule.id]
530571

531572
# work out if we need term_mapping or not
532573
term_mapping = None
533574
if "concept_id" in destination_field.field:
534-
if scan_report_concept.content_type.model_class() is ScanReportValue:
575+
if scan_report_concept.id in scan_report_concepts_with_values:
535576
term_mapping = {
536-
scan_report_values[scan_report_concept.object_id]: concept_id
577+
scan_report_values_id_to_value_map[
578+
scan_report_concept.object_id
579+
]: concept_id
537580
}
538581
else:
539582
term_mapping = concept_id
540583

541584
creation_type = scan_report_concept.creation_type
585+
542586
rules.append(
543587
{
544-
"rule_id": scan_report_concept_id,
588+
"rule_id": rule_scan_report_concept_id,
545589
"rule_name": concept_name,
546590
"destination_table": destination_table,
547591
"destination_field": destination_field,

changelog.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
Please append a line to the changelog for each change made.
44

5+
## v2.0.10
6+
### New features
7+
8+
### Improvements
9+
- Rewritten `get_mapping_rules_list()` function to greatly speed up the loading of the `/mapping_rules` page.
10+
11+
### Bugfixes
12+
13+
514
## v2.0.9
615
### New features
716

0 commit comments

Comments
 (0)