Skip to content

Commit

Permalink
⚡ [#1451] -- ensure that rendering a submission does not lead to an e…
Browse files Browse the repository at this point in the history
…xplosion of queries
  • Loading branch information
sergei-maertens committed Apr 29, 2022
1 parent 0e18ad2 commit 5ceba4c
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 3 deletions.
10 changes: 9 additions & 1 deletion src/openforms/submissions/form_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,15 @@ def evaluate_form_logic(
if _evaluated:
return configuration

rules = FormLogic.objects.filter(form=step.form_step.form)
# renderer evaluates logic for all steps at once, so we can avoid repeated queries
# by caching the rules on the form instance.
# Note that form.formlogic_set.all() is never cached by django, so we can't rely
# on that.
rules = getattr(submission.form, "_cached_logic_rules", None)
if rules is None:
rules = FormLogic.objects.filter(form=submission.form)
submission.form._cached_logic_rules = rules

submission_state = submission.load_execution_state()

for rule in rules:
Expand Down
3 changes: 2 additions & 1 deletion src/openforms/submissions/rendering/renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,12 @@ def get_children(self) -> Iterator["SubmissionStepNode"]:
"""
Produce only the direct child nodes.
"""
submission_data = self.submission.data
for step in self.steps:
new_configuration = evaluate_form_logic(
submission=self.submission,
step=step,
data=self.submission.data,
data=submission_data,
dirty=False,
request=self.dummy_request,
)
Expand Down
18 changes: 17 additions & 1 deletion src/openforms/submissions/tests/renderer/test_renderer.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from django.test import TestCase
from django.test import TestCase, override_settings

from rest_framework.reverse import reverse

Expand Down Expand Up @@ -103,3 +103,19 @@ def test_renderer_with_form_logic_and_disabled_step(self):
self.assertEqual(len(nodes), 2)
enabled_step_node = nodes[1]
self.assertEqual(enabled_step_node.step, self.sstep1)

def test_performance_num_queries(self):
"""
Assert that the number of queries stays low while rendering a submission.
"""
renderer = Renderer(
submission=self.submission, mode=RenderModes.pdf, as_html=True
)

# Expected queries:
# 1. Getting the merged data of the submission steps
# 2. Getting the submission steps for the given submission
# 3 & 4. Loading the submission execution state
# 5. Query the form logic rules for the submission form (and this is cached)
with self.assertNumQueries(5):
list(renderer)

0 comments on commit 5ceba4c

Please sign in to comment.