From 79653a414857e4f93918051843afbc1f7c9a7f99 Mon Sep 17 00:00:00 2001 From: Malcolm Tredinnick Date: Fri, 30 Nov 2007 04:44:32 +0000 Subject: [PATCH] queryset-refactor: Implemented filtering by output columns specified in extra(select=...). Refs #4002. git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@6762 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/db/models/sql/query.py | 12 ++++++++++-- django/db/models/sql/where.py | 6 +++++- tests/regressiontests/queries/models.py | 13 +++++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index 703d7a18b7..907903dc90 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -692,8 +692,16 @@ class Query(object): opts = self.model._meta alias = self.join((None, opts.db_table, None, None)) - field, target, unused, join_list, nullable = self.setup_joins(parts, - opts, alias, (connection == AND)) + try: + field, target, unused, join_list, nullable = self.setup_joins(parts, + opts, alias, (connection == AND)) + except TypeError, e: + if len(parts) != 1 or parts[0] not in self.extra_select: + raise e + # Filtering on some alias from extra(select=...) + self.where.add([None, parts[0], None, lookup_type, value], + connection) + return col = target.column alias = join_list[-1][-1] diff --git a/django/db/models/sql/where.py b/django/db/models/sql/where.py index 5fa1ae8096..6dc3e2d5ee 100644 --- a/django/db/models/sql/where.py +++ b/django/db/models/sql/where.py @@ -5,6 +5,7 @@ import datetime from django.utils import tree from django.db import connection +from django.db.models.fields import Field from datastructures import EmptyResultSet # Connection types @@ -96,7 +97,10 @@ class WhereNode(tree.Node): else: format = '%s %s' - params = field.get_db_prep_lookup(lookup_type, value) + if field: + params = field.get_db_prep_lookup(lookup_type, value) + else: + params = Field().get_db_prep_lookup(lookup_type, value) if lookup_type in connection.operators: return (format % (field_sql, diff --git a/tests/regressiontests/queries/models.py b/tests/regressiontests/queries/models.py index fe0940152d..ea87a2fd41 100644 --- a/tests/regressiontests/queries/models.py +++ b/tests/regressiontests/queries/models.py @@ -404,5 +404,18 @@ thus fail.) ... params.reverse() >>> Item.objects.extra(select=SortedDict(s), params=params).values('a','b')[0] {'a': u'one', 'b': u'two'} + +Bug #4002 +Attributes used in extra(select=...) are available for use in subsequent +order_by() and filter() calls. + +# Order by the number of tags attached to an item. +>>> l = Item.objects.extra(select={'count': 'select count(*) from queries_item_tags where queries_item_tags.item_id = queries_item.id'}).order_by('-count') +>>> [o.count for o in l] +[2, 2, 1, 0] + +# Filter those items that have exactly one tag attacjed. +>>> Item.objects.extra(select={'count': 'select count(*) from queries_item_tags where queries_item_tags.item_id = queries_item.id'}).filter(count=1) +[] """}