Author: mtredinnick
Date: 2007-10-23 23:22:23 -0500 (Tue, 23 Oct 2007)
New Revision: 6603
Modified:
django/branches/queryset-refactor/django/db/models/query.py
django/branches/queryset-refactor/django/db/models/sql/query.py
django/branches/queryset-refactor/docs/db-api.txt
django/branches/queryset-refactor/tests/regressiontests/queries/models.py
Log:
queryset-refactor: Added the ability to apply parameters to the select
fragments in QuerySet.extra(). Refs #2902
Modified: django/branches/queryset-refactor/django/db/models/query.py
===================================================================
--- django/branches/queryset-refactor/django/db/models/query.py 2007-10-23
19:11:15 UTC (rev 6602)
+++ django/branches/queryset-refactor/django/db/models/query.py 2007-10-24
04:22:23 UTC (rev 6603)
@@ -88,7 +88,6 @@
max_depth = self.query.max_depth
index_end = len(self.model._meta.fields)
extra_select = self.query.extra_select.keys()
- extra_select.sort()
for row in self.query.results_iter():
if fill_cache:
obj, index_end = get_cached_row(klass=self.model, row=row,
@@ -378,11 +377,7 @@
# names of the model fields to select.
def iterator(self):
- extra_select = self.query.extra_select.keys()
- extra_select.sort()
- if extra_select:
- self.field_names.extend([f for f in extra_select])
-
+ self.field_names.extend([f for f in self.query.extra_select.keys()])
for row in self.query.results_iter():
yield dict(zip(self.field_names, row))
@@ -409,7 +404,7 @@
except KeyError, e:
raise FieldDoesNotExist('%s has no field named %r'
% (opts.object_name, e.args[0]))
- field_names = self._fields
+ field_names = list(self._fields)
else:
fields = []
field_names = []
Modified: django/branches/queryset-refactor/django/db/models/sql/query.py
===================================================================
--- django/branches/queryset-refactor/django/db/models/sql/query.py
2007-10-23 19:11:15 UTC (rev 6602)
+++ django/branches/queryset-refactor/django/db/models/sql/query.py
2007-10-24 04:22:23 UTC (rev 6603)
@@ -10,7 +10,8 @@
import copy
import re
-from django.utils import tree
+from django.utils.tree import Node
+from django.utils.datastructures import SortedDict
from django.db.models.sql.where import WhereNode, AND, OR
from django.db.models.sql.datastructures import Count, Date
from django.db.models.fields import FieldDoesNotExist, Field
@@ -94,7 +95,7 @@
# These are for extensions. The contents are more or less appended
# verbatim to the appropriate clause.
- self.extra_select = {} # Maps col_alias -> col_sql.
+ self.extra_select = SortedDict() # Maps col_alias -> col_sql.
self.extra_tables = []
self.extra_where = []
self.extra_params = []
@@ -364,12 +365,8 @@
for f in self.model._meta.fields]
aliases = result[:]
- # We sort extra_select so that the result columns are in a well-defined
- # order (and thus QuerySet.iterator can extract them correctly).
- extra_select = self.extra_select.items()
- extra_select.sort()
result.extend(['(%s) AS %s' % (col, alias)
- for alias, col in extra_select])
+ for alias, col in self.extra_select.items()])
aliases.extend(self.extra_select.keys())
self._select_aliases = dict.fromkeys(aliases)
@@ -761,7 +758,7 @@
return
for child in q_object.children:
- if isinstance(child, tree.Node):
+ if isinstance(child, Node):
self.where.start_subtree(q_object.connection)
self.add_q(child)
self.where.end_subtree()
@@ -937,7 +934,7 @@
# level.
self.distinct = False
self.select = [select]
- self.extra_select = {}
+ self.extra_select = SortedDict()
def execute_sql(self, result_type=MULTI):
"""
Modified: django/branches/queryset-refactor/docs/db-api.txt
===================================================================
--- django/branches/queryset-refactor/docs/db-api.txt 2007-10-23 19:11:15 UTC
(rev 6602)
+++ django/branches/queryset-refactor/docs/db-api.txt 2007-10-24 04:22:23 UTC
(rev 6603)
@@ -820,6 +820,34 @@
some database backends, such as some MySQL versions, don't support
subqueries.
+ **New in Django development version**
+ In some rare cases, you might wish to pass parameters to the SQL fragments
+ in ``extra(select=...)```. Since the ``params`` attribute is a sequence
+ and the ``select`` attribute is a dictionary, some care is required so
+ that the parameters are matched up correctly with the extra select pieces.
+ Firstly, in this situation, you should use a
+ ``django.utils.datastructures.SortedDict`` for the ``select`` value, not
+ just a normal Python dictionary. Secondly, make sure that your parameters
+ for the ``select`` come first in the list and that you have not passed any
+ parameters to an earlier ``extra()`` call for this queryset.
+
+ This will work::
+
+ Blog.objects.extra(
+ select=SortedDict(('a', '%s'), ('b', '%s')),
+ params=('one', 'two'))
+
+ ... while this won't::
+
+ # Will not work!
+ Blog.objects.extra(where=['foo=%s'], params=('bar',)).extra(
+ select=SortedDict(('a', '%s'), ('b', '%s')),
+ params=('one', 'two'))
+
+ In the second example, the earlier ``params`` usage will mess up the later
+ one. So always put your extra select pieces in the first ``extra()`` call
+ if you need to use parameters in them.
+
``where`` / ``tables``
You can define explicit SQL ``WHERE`` clauses -- perhaps to perform
non-explicit joins -- by using ``where``. You can manually add tables to
Modified:
django/branches/queryset-refactor/tests/regressiontests/queries/models.py
===================================================================
--- django/branches/queryset-refactor/tests/regressiontests/queries/models.py
2007-10-23 19:11:15 UTC (rev 6602)
+++ django/branches/queryset-refactor/tests/regressiontests/queries/models.py
2007-10-24 04:22:23 UTC (rev 6603)
@@ -379,5 +379,20 @@
>>> q1 = Item.objects.order_by('name')
>>> id(q1) == id(q1.all())
False
+
+Bug #2902
+Parameters can be given to extra_select, *if* you use a SortedDict.
+
+(First we need to know which order the keys fall in "naturally" on your system,
+so we can put things in the wrong way around from normal. A normal dict would
+thus fail.)
+>>> from django.utils.datastructures import SortedDict
+>>> s = [('a', '%s'), ('b', '%s')]
+>>> params = ['one', 'two']
+>>> if {'a': 1, 'b': 2}.keys() == ['a', 'b']:
+... s.reverse()
+... params.reverse()
+>>> Item.objects.extra(select=SortedDict(s), params=params).values('a','b')[0]
+{'a': u'one', 'b': u'two'}
"""}
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---