Browse Source

Reduce the number of SQL queries used in the "Get Checks" API call

pull/456/head
Pēteris Caune 4 years ago
parent
commit
6f56ed7f92
No known key found for this signature in database GPG Key ID: E28D7679E9A9EDE2
4 changed files with 18 additions and 5 deletions
  1. +1
    -0
      CHANGELOG.md
  2. +4
    -2
      hc/api/models.py
  3. +11
    -2
      hc/api/tests/test_list_checks.py
  4. +2
    -1
      hc/api/views.py

+ 1
- 0
CHANGELOG.md View File

@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file.
- Update API to allow specifying channels by names (#440) - Update API to allow specifying channels by names (#440)
- When saving a phone number, remove any invisible unicode characers - When saving a phone number, remove any invisible unicode characers
- Update the read-only dashboard's CSS for better mobile support (#442) - Update the read-only dashboard's CSS for better mobile support (#442)
- Reduce the number of SQL queries used in the "Get Checks" API call
## v1.17.0 - 2020-10-14 ## v1.17.0 - 2020-10-14


+ 4
- 2
hc/api/models.py View File

@ -205,8 +205,10 @@ class Check(models.Model):
def channels_str(self): def channels_str(self):
""" Return a comma-separated string of assigned channel codes. """ """ Return a comma-separated string of assigned channel codes. """
codes = self.channel_set.order_by("code").values_list("code", flat=True)
return ",".join(map(str, codes))
# self.channel_set may already be prefetched.
# Sort in python to make sure we do't run additional queries
codes = [str(channel.code) for channel in self.channel_set.all()]
return ",".join(sorted(codes))
@property @property
def unique_key(self): def unique_key(self):


+ 11
- 2
hc/api/tests/test_list_checks.py View File

@ -37,7 +37,13 @@ class ListChecksTestCase(BaseTestCase):
return self.client.get("/api/v1/checks/", HTTP_X_API_KEY="X" * 32) return self.client.get("/api/v1/checks/", HTTP_X_API_KEY="X" * 32)
def test_it_works(self): def test_it_works(self):
r = self.get()
# Expect 3 queries:
# * check API key
# * retrieve checks
# * retrieve channel codes
with self.assertNumQueries(3):
r = self.get()
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
self.assertEqual(r["Access-Control-Allow-Origin"], "*") self.assertEqual(r["Access-Control-Allow-Origin"], "*")
@ -148,7 +154,10 @@ class ListChecksTestCase(BaseTestCase):
self.project.api_key_readonly = "R" * 32 self.project.api_key_readonly = "R" * 32
self.project.save() self.project.save()
r = self.client.get("/api/v1/checks/", HTTP_X_API_KEY="R" * 32)
# Expect a query to check the API key, and a query to retrieve checks
with self.assertNumQueries(2):
r = self.client.get("/api/v1/checks/", HTTP_X_API_KEY="R" * 32)
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
# When using readonly keys, the ping URLs should not be exposed: # When using readonly keys, the ping URLs should not be exposed:


+ 2
- 1
hc/api/views.py View File

@ -162,7 +162,8 @@ def _update(check, spec):
@authorize_read @authorize_read
def get_checks(request): def get_checks(request):
q = Check.objects.filter(project=request.project) q = Check.objects.filter(project=request.project)
q = q.prefetch_related("channel_set")
if not request.readonly:
q = q.prefetch_related("channel_set")
tags = set(request.GET.getlist("tag")) tags = set(request.GET.getlist("tag"))
for tag in tags: for tag in tags:


Loading…
Cancel
Save