mirror of
https://github.com/django/django.git
synced 2025-07-07 03:09:22 +00:00
queryset-refactor: Added the ability to apply parameters to the select
fragments in QuerySet.extra(). Refs #2902 git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@6603 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
abcb70e524
commit
f951d97d99
@ -88,7 +88,6 @@ class _QuerySet(object):
|
|||||||
max_depth = self.query.max_depth
|
max_depth = self.query.max_depth
|
||||||
index_end = len(self.model._meta.fields)
|
index_end = len(self.model._meta.fields)
|
||||||
extra_select = self.query.extra_select.keys()
|
extra_select = self.query.extra_select.keys()
|
||||||
extra_select.sort()
|
|
||||||
for row in self.query.results_iter():
|
for row in self.query.results_iter():
|
||||||
if fill_cache:
|
if fill_cache:
|
||||||
obj, index_end = get_cached_row(klass=self.model, row=row,
|
obj, index_end = get_cached_row(klass=self.model, row=row,
|
||||||
@ -378,11 +377,7 @@ class ValuesQuerySet(QuerySet):
|
|||||||
# names of the model fields to select.
|
# names of the model fields to select.
|
||||||
|
|
||||||
def iterator(self):
|
def iterator(self):
|
||||||
extra_select = self.query.extra_select.keys()
|
self.field_names.extend([f for f in self.query.extra_select.keys()])
|
||||||
extra_select.sort()
|
|
||||||
if extra_select:
|
|
||||||
self.field_names.extend([f for f in extra_select])
|
|
||||||
|
|
||||||
for row in self.query.results_iter():
|
for row in self.query.results_iter():
|
||||||
yield dict(zip(self.field_names, row))
|
yield dict(zip(self.field_names, row))
|
||||||
|
|
||||||
@ -409,7 +404,7 @@ class ValuesQuerySet(QuerySet):
|
|||||||
except KeyError, e:
|
except KeyError, e:
|
||||||
raise FieldDoesNotExist('%s has no field named %r'
|
raise FieldDoesNotExist('%s has no field named %r'
|
||||||
% (opts.object_name, e.args[0]))
|
% (opts.object_name, e.args[0]))
|
||||||
field_names = self._fields
|
field_names = list(self._fields)
|
||||||
else:
|
else:
|
||||||
fields = []
|
fields = []
|
||||||
field_names = []
|
field_names = []
|
||||||
|
@ -10,7 +10,8 @@ all about the internals of models in order to get the information it needs.
|
|||||||
import copy
|
import copy
|
||||||
import re
|
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.where import WhereNode, AND, OR
|
||||||
from django.db.models.sql.datastructures import Count, Date
|
from django.db.models.sql.datastructures import Count, Date
|
||||||
from django.db.models.fields import FieldDoesNotExist, Field
|
from django.db.models.fields import FieldDoesNotExist, Field
|
||||||
@ -94,7 +95,7 @@ class Query(object):
|
|||||||
|
|
||||||
# These are for extensions. The contents are more or less appended
|
# These are for extensions. The contents are more or less appended
|
||||||
# verbatim to the appropriate clause.
|
# 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_tables = []
|
||||||
self.extra_where = []
|
self.extra_where = []
|
||||||
self.extra_params = []
|
self.extra_params = []
|
||||||
@ -364,12 +365,8 @@ class Query(object):
|
|||||||
for f in self.model._meta.fields]
|
for f in self.model._meta.fields]
|
||||||
aliases = result[:]
|
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)
|
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())
|
aliases.extend(self.extra_select.keys())
|
||||||
|
|
||||||
self._select_aliases = dict.fromkeys(aliases)
|
self._select_aliases = dict.fromkeys(aliases)
|
||||||
@ -761,7 +758,7 @@ class Query(object):
|
|||||||
return
|
return
|
||||||
|
|
||||||
for child in q_object.children:
|
for child in q_object.children:
|
||||||
if isinstance(child, tree.Node):
|
if isinstance(child, Node):
|
||||||
self.where.start_subtree(q_object.connection)
|
self.where.start_subtree(q_object.connection)
|
||||||
self.add_q(child)
|
self.add_q(child)
|
||||||
self.where.end_subtree()
|
self.where.end_subtree()
|
||||||
@ -937,7 +934,7 @@ class Query(object):
|
|||||||
# level.
|
# level.
|
||||||
self.distinct = False
|
self.distinct = False
|
||||||
self.select = [select]
|
self.select = [select]
|
||||||
self.extra_select = {}
|
self.extra_select = SortedDict()
|
||||||
|
|
||||||
def execute_sql(self, result_type=MULTI):
|
def execute_sql(self, result_type=MULTI):
|
||||||
"""
|
"""
|
||||||
|
@ -820,6 +820,34 @@ of the arguments is required, but you should use at least one of them.
|
|||||||
some database backends, such as some MySQL versions, don't support
|
some database backends, such as some MySQL versions, don't support
|
||||||
subqueries.
|
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``
|
``where`` / ``tables``
|
||||||
You can define explicit SQL ``WHERE`` clauses -- perhaps to perform
|
You can define explicit SQL ``WHERE`` clauses -- perhaps to perform
|
||||||
non-explicit joins -- by using ``where``. You can manually add tables to
|
non-explicit joins -- by using ``where``. You can manually add tables to
|
||||||
|
@ -379,5 +379,20 @@ The all() method on querysets returns a copy of the queryset.
|
|||||||
>>> q1 = Item.objects.order_by('name')
|
>>> q1 = Item.objects.order_by('name')
|
||||||
>>> id(q1) == id(q1.all())
|
>>> id(q1) == id(q1.all())
|
||||||
False
|
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'}
|
||||||
"""}
|
"""}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user