Add support for joining specific test attributes to the TKO get_test_view() method and friends (including grouping friends). This required a number of cleanups to the code in general. The two big changes were:
* making application of "presentation" arguments (sorting and paging) optional in query_objects() and separately applicables
* getting rid of the explicit passing of extra_select_fields in grouping code, and using Django query builtin extra selects instead (i.e. query.extra(select=...))
Signed-off-by: Steve Howard <showard@google.com>
git-svn-id: http://test.kernel.org/svn/autotest/trunk@3806 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/frontend/afe/model_logic.py b/frontend/afe/model_logic.py
index 601b9c3..39add70 100644
--- a/frontend/afe/model_logic.py
+++ b/frontend/afe/model_logic.py
@@ -617,8 +617,52 @@
self.save()
+ # see query_objects()
+ _SPECIAL_FILTER_KEYS = ('query_start', 'query_limit', 'sort_by',
+ 'extra_args', 'extra_where', 'no_distinct')
+
+
@classmethod
- def query_objects(cls, filter_data, valid_only=True, initial_query=None):
+ def _extract_special_params(cls, filter_data):
+ """
+ @returns a tuple of dicts (special_params, regular_filters), where
+ special_params contains the parameters we handle specially and
+ regular_filters is the remaining data to be handled by Django.
+ """
+ regular_filters = dict(filter_data)
+ special_params = {}
+ for key in cls._SPECIAL_FILTER_KEYS:
+ if key in regular_filters:
+ special_params[key] = regular_filters.pop(key)
+ return special_params, regular_filters
+
+
+ @classmethod
+ def apply_presentation(cls, query, filter_data):
+ """
+ Apply presentation parameters -- sorting and paging -- to the given
+ query.
+ @returns new query with presentation applied
+ """
+ special_params, _ = cls._extract_special_params(filter_data)
+ sort_by = special_params.get('sort_by', None)
+ if sort_by:
+ assert isinstance(sort_by, list) or isinstance(sort_by, tuple)
+ query = query.order_by(*sort_by)
+
+ query_start = special_params.get('query_start', None)
+ query_limit = special_params.get('query_limit', None)
+ if query_start is not None:
+ if query_limit is None:
+ raise ValueError('Cannot pass query_start without query_limit')
+ # query_limit is passed as a page size
+ query = query[query_start:(query_start + query_limit)]
+ return query
+
+
+ @classmethod
+ def query_objects(cls, filter_data, valid_only=True, initial_query=None,
+ apply_presentation=True):
"""\
Returns a QuerySet object for querying the given model_class
with the given filter_data. Optional special arguments in
@@ -630,43 +674,37 @@
-extra_args: keyword args to pass to query.extra() (see Django
DB layer documentation)
-extra_where: extra WHERE clause to append
+ -no_distinct: if True, a DISTINCT will not be added to the SELECT
"""
- filter_data = dict(filter_data) # copy so we don't mutate the original
- query_start = filter_data.pop('query_start', None)
- query_limit = filter_data.pop('query_limit', None)
- if query_start and not query_limit:
- raise ValueError('Cannot pass query_start without '
- 'query_limit')
- sort_by = filter_data.pop('sort_by', None)
- extra_args = filter_data.pop('extra_args', {})
- extra_where = filter_data.pop('extra_where', None)
- if extra_where:
- # escape %'s
- extra_where = cls.objects.escape_user_sql(extra_where)
- extra_args.setdefault('where', []).append(extra_where)
- use_distinct = not filter_data.pop('no_distinct', False)
+ special_params, regular_filters = cls._extract_special_params(
+ filter_data)
if initial_query is None:
if valid_only:
initial_query = cls.get_valid_manager()
else:
initial_query = cls.objects
- query = initial_query.filter(**filter_data)
+
+ query = initial_query.filter(**regular_filters)
+
+ use_distinct = not special_params.get('no_distinct', False)
if use_distinct:
query = query.distinct()
- # other arguments
+ extra_args = special_params.get('extra_args', {})
+ extra_where = special_params.get('extra_where', None)
+ if extra_where:
+ # escape %'s
+ extra_where = cls.objects.escape_user_sql(extra_where)
+ extra_args.setdefault('where', []).append(extra_where)
if extra_args:
query = query.extra(**extra_args)
query = query._clone(klass=ReadonlyQuerySet)
- # sorting + paging
- if sort_by:
- assert isinstance(sort_by, list) or isinstance(sort_by, tuple)
- query = query.order_by(*sort_by)
- if query_start is not None and query_limit is not None:
- query_limit += query_start
- return query[query_start:query_limit]
+ if apply_presentation:
+ query = cls.apply_presentation(query, filter_data)
+
+ return query
@classmethod
@@ -695,12 +733,13 @@
@classmethod
- def list_objects(cls, filter_data, initial_query=None, fields=None):
+ def list_objects(cls, filter_data, initial_query=None):
"""\
Like query_objects, but return a list of dictionaries.
"""
query = cls.query_objects(filter_data, initial_query=initial_query)
- field_dicts = [model_object.get_object_dict(fields)
+ extra_fields = query.query.extra_select.keys()
+ field_dicts = [model_object.get_object_dict(extra_fields=extra_fields)
for model_object in query]
return field_dicts
@@ -741,12 +780,15 @@
return result_objects
- def get_object_dict(self, fields=None):
+ def get_object_dict(self, extra_fields=None):
"""\
- Return a dictionary mapping fields to this object's values.
+ Return a dictionary mapping fields to this object's values. @param
+ extra_fields: list of extra attribute names to include, in addition to
+ the fields defined on this object.
"""
- if fields is None:
- fields = self.get_field_dict().iterkeys()
+ fields = self.get_field_dict().keys()
+ if extra_fields:
+ fields += extra_fields
object_dict = dict((field_name, getattr(self, field_name))
for field_name in fields)
self.clean_object_dicts([object_dict])