Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 0cb677d

Browse files
authored
fix select_related usage (#24)
* fix select_related usage In order to optimize the query, we need to select foreign key references as well from the database. So all foreign keys in the query are passed as parameters of select_related function * remove extra logging statement Signed-off-by: Priyank Singh <[email protected]>
1 parent b3290db commit 0cb677d

File tree

3 files changed

+31
-35
lines changed

3 files changed

+31
-35
lines changed

bridgeql/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"""
1515

1616
__title__ = 'BridgeQL'
17-
__version__ = '0.1.15'
17+
__version__ = '0.1.16'
1818
__license__ = 'BSD 2-Clause'
1919
__copyright__ = 'Copyright © 2023 VMware, Inc. All rights reserved.'
2020

bridgeql/django/models.py

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ def _inject_params(self):
4747
if not any((self.app_name, self.model_name)):
4848
raise InvalidRequest('app_name or model_name missing')
4949

50+
@property
51+
def fk_refs_in_fields(self):
52+
refs = []
53+
for field in self.fields:
54+
if '__' in field:
55+
refs.append(field.rsplit('__', 1)[0])
56+
return refs
57+
5058

5159
class ModelConfig(object):
5260
def __init__(self, app_name, model_name):
@@ -175,23 +183,10 @@ def _apply_opts(self):
175183
elif qset_opt == 'limit':
176184
self.qset = self.qset[:self.params.limit]
177185
elif isinstance(value, list):
178-
# handle values case separately
179-
if qset_opt == 'values':
180-
# list of parameters passed in values function
181-
values_params = set(value) - \
182-
self.model_config.get_properties()
183-
# list of properties handled separately
184-
properties = set(value) - values_params
185-
try:
186-
# qset.values(*fields) is called but not yet evaluated
187-
qset_values = func(*values_params)
188-
except FieldError as e:
189-
raise InvalidModelFieldName(str(e))
190-
if self.query_has_properties():
191-
# queryset evaluated
192-
qset_values = self._add_properties(
193-
qset_values, properties)
194-
self.qset = qset_values
186+
# handle values case where property is passed in fields
187+
if qset_opt == 'values' and self.query_has_properties():
188+
# returns DBRows instance
189+
self.qset = self._add_fields()
195190
else:
196191
try:
197192
self.qset = func(*value)
@@ -207,24 +202,25 @@ def query_has_properties(self):
207202
return bool(set(self.params.fields).intersection(
208203
self.model_config.get_properties()))
209204

210-
def _add_properties(self, db_rows, query_properties):
211-
# evaluate queryset values
212-
db_rows = list(db_rows)
205+
def _add_fields(self):
213206
qset_values = DBRows()
214-
# skipping select_related call, expecting
215-
# properties will not have references call
216-
# like machine.os.arch in any of the machine's property
217-
logger.debug('Request parameters: %s \nQuery (2nd call): %s\n',
207+
self.qset = self.qset.select_related(*self.params.fk_refs_in_fields)
208+
logger.debug('Request parameters: %s \nQuery: %s\n',
218209
self.params.params, self.qset.query)
219-
for i, row in enumerate(self.qset):
220-
for field in query_properties:
221-
try:
222-
model_property = getattr(row, field)
223-
except AttributeError:
224-
raise InvalidModelFieldName(
225-
'Query field "%s" does not exists.' % field)
226-
db_rows[i][field] = model_property
227-
qset_values.append(db_rows[i])
210+
for row in self.qset:
211+
model_fields = {}
212+
for field in self.params.fields:
213+
attr = row
214+
for ref in field.split('__'):
215+
try:
216+
attr = getattr(attr, ref)
217+
if attr is None:
218+
break
219+
except AttributeError:
220+
raise InvalidModelFieldName(
221+
'Invalid query for field %s in %s.' % (ref, attr))
222+
model_fields[field] = attr
223+
qset_values.append(model_fields)
228224
return qset_values
229225

230226
def queryset(self):

tests/server/machine/tests/test_api_reader.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def test_get_machine(self):
2727
'filter': {
2828
'name': 'machine-name-1'
2929
},
30-
'fields': ['ip', 'name', 'created_at', 'stats']
30+
'fields': ['ip', 'name', 'created_at', 'stats', 'os__name']
3131
}
3232
resp = self.client.get(self.url, {'payload': json.dumps(self.params)})
3333
self.assertEqual(resp.status_code, 200)

0 commit comments

Comments
 (0)