Skip to content

Commit b322560

Browse files
authored
Merge pull request #153 from NHSDigital/dtos-9252-optimize-fetching
[DTOS-9252] Optimise queries a bit
2 parents 247e7bf + 76a3962 commit b322560

15 files changed

Lines changed: 112 additions & 32 deletions

File tree

manage_breast_screening/clinics/models.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,9 @@ class TimeOfDay:
9797

9898
objects = ClinicQuerySet.as_manager()
9999

100+
@property
100101
def current_status(self):
101-
return self.statuses.first()
102+
return self.statuses.order_by("-created_at").first()
102103

103104
def session_type(self):
104105
start_hour = self.starts_at.hour

manage_breast_screening/clinics/presenters.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from functools import cached_property
2+
13
from django.urls import reverse
24

35
from ..core.utils.date_formatting import format_date, format_time_range
@@ -12,7 +14,7 @@ def __init__(self, filtered_clinics, filter, counts_by_filter):
1214
self.counts_by_filter = counts_by_filter
1315
self.filter = filter
1416

15-
@property
17+
@cached_property
1618
def heading(self):
1719
if self.filter == "today":
1820
return "Today’s clinics"
@@ -42,9 +44,9 @@ def __init__(self, clinic):
4244
self.type = clinic.get_type_display()
4345
self.risk_type = clinic.get_risk_type_display()
4446

45-
@property
47+
@cached_property
4648
def state(self):
47-
status = self._clinic.current_status()
49+
status = self._clinic.current_status
4850
value = status.state
4951
text = status.get_state_display()
5052

@@ -53,7 +55,7 @@ def state(self):
5355
"classes": "nhsuk-tag--" + self.STATUS_COLORS[value],
5456
}
5557

56-
@property
58+
@cached_property
5759
def setting_name(self):
5860
return self._clinic.setting.name
5961

@@ -67,7 +69,7 @@ def __init__(self, clinic_id, appointments, filter, counts_by_filter):
6769
self.counts_by_filter = counts_by_filter
6870
self.clinic_id = clinic_id
6971

70-
@property
72+
@cached_property
7173
def secondary_nav_data(self):
7274
filters = [
7375
{

manage_breast_screening/clinics/tests/test_models.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
@pytest.mark.django_db
1414
def test_clinic_current_status():
1515
clinic = ClinicFactory.create(current_status=models.ClinicStatus.SCHEDULED)
16-
assert clinic.current_status().state == models.ClinicStatus.SCHEDULED
16+
clinic.statuses.create(state=models.ClinicStatus.CANCELLED)
17+
assert clinic.statuses.first().state == models.ClinicStatus.CANCELLED
18+
assert clinic.current_status.state == models.ClinicStatus.CANCELLED
1719

1820

1921
@pytest.mark.django_db

manage_breast_screening/clinics/tests/test_presenters.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def mock_clinic():
2424
}
2525
mock.get_type_display.return_value = "Screening"
2626
mock.get_risk_type_display.return_value = "Routine"
27-
mock.current_status.return_value = ClinicStatusFactory.build()
27+
mock.current_status = ClinicStatusFactory.build()
2828

2929
return mock
3030

manage_breast_screening/clinics/views.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ def clinic_list(request, filter="today"):
1818

1919

2020
def clinic(request, id, filter="remaining"):
21-
clinic = Clinic.objects.prefetch_related("setting").get(id=id)
21+
clinic = Clinic.objects.select_related("setting").get(id=id)
2222
presented_clinic = ClinicPresenter(clinic)
2323
appointments = (
2424
Appointment.objects.for_clinic_and_filter(clinic, filter)
25-
.select_related("clinic_slot", "screening_episode__participant")
25+
.prefetch_related("statuses")
26+
.select_related("clinic_slot__clinic", "screening_episode__participant")
2627
.order_by("clinic_slot__starts_at")
2728
)
2829
counts_by_filter = Appointment.objects.filter_counts_for_clinic(clinic)

manage_breast_screening/config/settings.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,14 @@ def boolean_env(key, default=None):
7474
"django.middleware.clickjacking.XFrameOptionsMiddleware",
7575
]
7676

77+
if DEBUG:
78+
INTERNAL_IPS = ["127.0.0.1"]
79+
80+
DEBUG_TOOLBAR = DEBUG
81+
if DEBUG_TOOLBAR:
82+
INSTALLED_APPS.append("debug_toolbar")
83+
MIDDLEWARE.insert(0, "debug_toolbar.middleware.DebugToolbarMiddleware")
84+
7785
ROOT_URLCONF = "manage_breast_screening.core.urls"
7886

7987
TEMPLATES = [

manage_breast_screening/config/settings_test.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@
1010
},
1111
}
1212

13+
1314
MIDDLEWARE.remove(
1415
"whitenoise.middleware.WhiteNoiseMiddleware",
1516
)
17+
18+
if DEBUG:
19+
INSTALLED_APPS.remove("debug_toolbar")
20+
MIDDLEWARE.remove("debug_toolbar.middleware.DebugToolbarMiddleware")
21+
DEBUG_TOOLBAR = False

manage_breast_screening/core/urls.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
1616
"""
1717

18+
from django.conf import settings
1819
from django.contrib import admin
1920
from django.urls import include, path
2021
from django.views.generic.base import RedirectView
@@ -37,3 +38,10 @@
3738
),
3839
path("", RedirectView.as_view(pattern_name="clinics:index"), name="home"),
3940
]
41+
42+
if settings.DEBUG_TOOLBAR:
43+
from debug_toolbar.toolbar import debug_toolbar_urls
44+
45+
urlpatterns = [
46+
*urlpatterns,
47+
] + debug_toolbar_urls()

manage_breast_screening/mammograms/presenters.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from functools import cached_property
2+
13
from django.urls import reverse
24

35
from ..core.utils.date_formatting import format_date, format_relative_date, format_time
@@ -42,9 +44,9 @@ def present_secondary_nav(id):
4244

4345

4446
class AppointmentPresenter:
45-
def __init__(self, appointment):
47+
def __init__(self, appointment, last_known_screening=None):
4648
self._appointment = appointment
47-
self._last_known_screening = appointment.screening_episode.previous()
49+
self._last_known_screening = last_known_screening
4850

4951
self.allStatuses = AppointmentStatus
5052
self.id = appointment.id
@@ -53,17 +55,18 @@ def __init__(self, appointment):
5355
appointment.screening_episode.participant
5456
)
5557

56-
@property
58+
@cached_property
5759
def participant_url(self):
5860
return self.participant.url
5961

60-
@property
62+
@cached_property
6163
def start_time(self):
6264
return self.clinic_slot.starts_at
6365

64-
@property
66+
@cached_property
6567
def current_status(self):
6668
current_status = self._appointment.current_status
69+
6770
colour = status_colour(current_status.state)
6871

6972
return {
@@ -73,7 +76,7 @@ def current_status(self):
7376
"is_confirmed": current_status.state == AppointmentStatus.CONFIRMED,
7477
}
7578

76-
@property
79+
@cached_property
7780
def last_known_screening(self):
7881
return (
7982
{
@@ -98,17 +101,17 @@ def __init__(self, clinic_slot):
98101

99102
self.clinic_id = self._clinic.id
100103

101-
@property
104+
@cached_property
102105
def clinic_type(self):
103106
return self._clinic.get_type_display().capitalize()
104107

105-
@property
108+
@cached_property
106109
def slot_time_and_clinic_date(self):
107110
clinic_slot = self._clinic_slot
108111
clinic = self._clinic
109112

110113
return f"{format_time(clinic_slot.starts_at)} ({clinic_slot.duration_in_minutes} minutes) - {format_date(clinic.starts_at)} ({format_relative_date(clinic.starts_at)})"
111114

112-
@property
115+
@cached_property
113116
def starts_at(self):
114117
return format_time(self._clinic_slot.starts_at)

manage_breast_screening/mammograms/tests/test_presenters.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ def test_status(
7272
def test_last_known_screening(self, mock_appointment):
7373
mock_screening = MagicMock(spec=ScreeningEpisode)
7474
mock_screening.created_at = datetime(2015, 1, 1)
75-
mock_appointment.screening_episode.previous.return_value = mock_screening
75+
last_known_screening = mock_screening
7676

77-
result = AppointmentPresenter(mock_appointment)
77+
result = AppointmentPresenter(mock_appointment, last_known_screening)
7878

7979
assert result.last_known_screening == {
8080
"date": "1 January 2015",

0 commit comments

Comments
 (0)