Skip to content

Commit 7dfdbec

Browse files
authored
Merge pull request #163 from novafloss/157_deduplicate_queries_retrieve_builder_view
Deduplicate queries retrieve builder view
2 parents f18f1c7 + dbb8e64 commit 7dfdbec

File tree

7 files changed

+79
-33
lines changed

7 files changed

+79
-33
lines changed

CHANGELOG.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ master (unreleased)
88
* Added a make target to install the demo site.
99
* Added django-perf-rec module for tests and improved SQL queries in `ContextFormDetailView` (#54, #154, #160).
1010
* Added test to count queries on dynamic form queryset + improve performances (#155, #156, #162).
11+
* Added test to count queries on retrieve builder view + improve performances by removing duplicate queries (#157, #158, #163).
1112

1213

1314
Release 0.5.0 (2017-01-10)

demo/tests/perfs/test_end_point.perf.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,10 @@ RenderContextSerializer.test_queryset:
44
- db: SELECT ... FROM "formidable_item" WHERE "formidable_item"."field_id" IN (...) ORDER BY "formidable_item"."order" ASC
55
- db: SELECT ... FROM "formidable_validation" WHERE "formidable_validation"."field_id" IN (...)
66
- db: SELECT ... FROM "formidable_default" WHERE "formidable_default"."field_id" IN (...)
7+
RenderSerializerTestCase.test_queryset:
8+
- db: 'SELECT ... FROM "formidable_field" WHERE "formidable_field"."form_id" = # ORDER BY "formidable_field"."order" ASC'
9+
- db: SELECT ... FROM "formidable_item" WHERE "formidable_item"."field_id" IN (...) ORDER BY "formidable_item"."order" ASC
10+
- db: SELECT ... FROM "formidable_default" WHERE "formidable_default"."field_id" IN (...)
11+
- db: SELECT ... FROM "formidable_validation" WHERE "formidable_validation"."field_id" IN (...)
12+
- db: SELECT ... FROM "formidable_access" WHERE "formidable_access"."field_id" IN (...)
13+
- db: 'SELECT ... FROM "formidable_preset" WHERE "formidable_preset"."form_id" = #'

demo/tests/perfs/tests_integration.perf.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,11 @@ TestContextFormEndPoint.test_queryset:
66
- db: SELECT ... FROM "formidable_item" WHERE "formidable_item"."field_id" IN (...) ORDER BY "formidable_item"."order" ASC
77
- db: SELECT ... FROM "formidable_validation" WHERE "formidable_validation"."field_id" IN (...)
88
- db: SELECT ... FROM "formidable_default" WHERE "formidable_default"."field_id" IN (...)
9+
UpdateFormTestCase.test_queryset_on_get:
10+
- db: 'SELECT ... FROM "formidable_formidable" WHERE "formidable_formidable"."id" = #'
11+
- db: 'SELECT ... FROM "formidable_field" WHERE "formidable_field"."form_id" = # ORDER BY "formidable_field"."order" ASC'
12+
- db: SELECT ... FROM "formidable_item" WHERE "formidable_item"."field_id" IN (...) ORDER BY "formidable_item"."order" ASC
13+
- db: SELECT ... FROM "formidable_default" WHERE "formidable_default"."field_id" IN (...)
14+
- db: SELECT ... FROM "formidable_validation" WHERE "formidable_validation"."field_id" IN (...)
15+
- db: SELECT ... FROM "formidable_access" WHERE "formidable_access"."field_id" IN (...)
16+
- db: 'SELECT ... FROM "formidable_preset" WHERE "formidable_preset"."form_id" = #'

demo/tests/test_end_point.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,20 @@ def test_separator_field(self):
196196
self.assertNotIn('label', data)
197197
self.assertNotIn('help_text', data)
198198

199+
def test_queryset(self):
200+
class MyTestForm(FormidableForm):
201+
first_name = fields.CharField(default='foo')
202+
last_name = fields.CharField()
203+
origin = fields.ChoiceField(choices=(
204+
('fr', 'France'),
205+
('us', 'United States'),
206+
))
207+
208+
formidable = MyTestForm.to_formidable(label='test')
209+
serializer = FormidableSerializer(instance=formidable)
210+
with django_perf_rec.record(path='perfs/'):
211+
serializer.data
212+
199213

200214
class RenderContextSerializer(TestCase):
201215

demo/tests/tests_integration.py

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from copy import deepcopy
66

77
from django.core.urlresolvers import reverse
8+
import django_perf_rec
89

910
from freezegun import freeze_time
1011
from rest_framework.test import APITestCase
@@ -17,6 +18,33 @@
1718
from . import form_data, form_data_items
1819

1920

21+
class MyTestForm(FormidableForm):
22+
23+
name = fields.CharField(label='Name', accesses={'jedi': 'REQUIRED'})
24+
birth_date = fields.DateField(
25+
label='Your Birth Date',
26+
validators=[
27+
validators.AgeAboveValidator(
28+
21, message='You cannot be a jedi until your 21'
29+
),
30+
validators.DateIsInFuture(False)
31+
],
32+
accesses={'jedi': 'REQUIRED'},
33+
)
34+
out_date = fields.DateField(
35+
validators=[validators.DateIsInFuture(True)]
36+
)
37+
weapons = fields.ChoiceField(choices=[
38+
('gun', 'blaster'), ('sword', 'light saber')
39+
])
40+
salary = fields.IntegerField(
41+
validators=[
42+
validators.GTValidator(0), validators.LTEValidator(25)
43+
],
44+
accesses={'jedi': 'HIDDEN', 'jedi-master': 'REQUIRED'}
45+
)
46+
47+
2048
class CreateFormTestCase(APITestCase):
2149

2250
def test_simple(self):
@@ -73,6 +101,11 @@ def test_with_unknown_accesses(self):
73101

74102
class UpdateFormTestCase(APITestCase):
75103

104+
@classmethod
105+
def setUpClass(cls):
106+
super(UpdateFormTestCase, cls).setUpClass()
107+
cls.formidable_form = MyTestForm.to_formidable(label='test')
108+
76109
def setUp(self):
77110
super(UpdateFormTestCase, self).setUp()
78111
self.form = Formidable.objects.create(
@@ -164,6 +197,12 @@ def test_delete_field_on_update(self):
164197
access_id="jedi-master", level="READONLY"
165198
).exists())
166199

200+
def test_queryset_on_get(self):
201+
with django_perf_rec.record(path='perfs/'):
202+
self.client.get(reverse(
203+
'formidable:form_detail', args=[self.formidable_form.pk])
204+
)
205+
167206

168207
class TestAccess(APITestCase):
169208

@@ -184,34 +223,9 @@ def test_get(self):
184223

185224
class TestChain(APITestCase):
186225

187-
class MyTestForm(FormidableForm):
188-
189-
name = fields.CharField(label='Name', accesses={'jedi': 'REQUIRED'})
190-
birth_date = fields.DateField(
191-
label='Your Birth Date', validators=[
192-
validators.AgeAboveValidator(
193-
21, message='You cannot be a jedi until your 21'
194-
),
195-
validators.DateIsInFuture(False)
196-
],
197-
accesses={'jedi': 'REQUIRED'},
198-
)
199-
out_date = fields.DateField(
200-
validators=[validators.DateIsInFuture(True)]
201-
)
202-
weapons = fields.ChoiceField(choices=[
203-
('gun', 'blaster'), ('sword', 'light saber')
204-
])
205-
salary = fields.IntegerField(
206-
validators=[
207-
validators.GTValidator(0), validators.LTEValidator(25)
208-
],
209-
accesses={'jedi': 'HIDDEN', 'jedi-master': 'REQUIRED'}
210-
)
211-
212226
def setUp(self):
213227
super(APITestCase, self).setUp()
214-
self.form = self.MyTestForm.to_formidable(label='Jedi Form')
228+
self.form = MyTestForm.to_formidable(label='Jedi Form')
215229
self.assertTrue(self.form.pk)
216230

217231
@freeze_time('2021-01-01')

formidable/serializers/fields.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ def validate(self, validated_data):
4747

4848
return validated_data
4949

50+
def get_attribute(self, instance):
51+
qs = super(FieldListSerializer, self).get_attribute(instance)
52+
qs = qs.prefetch_related(
53+
Prefetch('items', queryset=Item.objects.order_by('order')),
54+
'defaults', 'validations', 'accesses'
55+
)
56+
return qs.order_by('order')
57+
5058

5159
class FieldSerializer(WithNestedSerializer):
5260

formidable/views.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
from django.conf import settings
77
from django.core.exceptions import ImproperlyConfigured
8-
from django.db.models import Prefetch
98

109
import six
1110
from rest_framework import exceptions
@@ -21,7 +20,7 @@
2120
FileFieldBuilder, FormFieldFactory, SkipField
2221
)
2322
from formidable.forms.validations.presets import presets_register
24-
from formidable.models import Field, Formidable
23+
from formidable.models import Formidable
2524
from formidable.serializers import FormidableSerializer, SimpleAccessSerializer
2625
from formidable.serializers.forms import ContextFormSerializer
2726
from formidable.serializers.presets import PresetsSerializer
@@ -176,11 +175,6 @@ class FormidableDetail(six.with_metaclass(MetaClassView,
176175
success_callback_settings = 'FORMIDABLE_POST_UPDATE_CALLBACK_SUCCESS'
177176
failure_callback_settings = 'FORMIDABLE_POST_UPDATE_CALLBACK_FAIL'
178177

179-
def get_queryset(self):
180-
qs = super(FormidableDetail, self).get_queryset()
181-
field_qs = Field.objects.order_by('order')
182-
return qs.prefetch_related(Prefetch('fields', queryset=field_qs))
183-
184178

185179
class FormidableCreate(six.with_metaclass(MetaClassView,
186180
CallbackMixin, CreateAPIView)):

0 commit comments

Comments
 (0)