Django

Code

Changeset 6603

Show
Ignore:
Timestamp:
10/23/07 23:22:23 (10 months ago)
Author:
mtredinnick
Message:

queryset-refactor: Added the ability to apply parameters to the select
fragments in QuerySet?.extra(). Refs #2902

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/queryset-refactor/django/db/models/query.py

    r6600 r6603  
    8989        index_end = len(self.model._meta.fields) 
    9090        extra_select = self.query.extra_select.keys() 
    91         extra_select.sort() 
    9291        for row in self.query.results_iter(): 
    9392            if fill_cache: 
     
    379378 
    380379    def iterator(self): 
    381         extra_select = self.query.extra_select.keys() 
    382         extra_select.sort() 
    383         if extra_select: 
    384             self.field_names.extend([f for f in extra_select]) 
    385  
     380        self.field_names.extend([f for f in self.query.extra_select.keys()]) 
    386381        for row in self.query.results_iter(): 
    387382            yield dict(zip(self.field_names, row)) 
     
    410405                    raise FieldDoesNotExist('%s has no field named %r' 
    411406                                % (opts.object_name, e.args[0])) 
    412                 field_names = self._fields 
     407                field_names = list(self._fields) 
    413408            else: 
    414409                fields = [] 
  • django/branches/queryset-refactor/django/db/models/sql/query.py

    r6521 r6603  
    1111import re 
    1212 
    13 from django.utils import tree 
     13from django.utils.tree import Node 
     14from django.utils.datastructures import SortedDict 
    1415from django.db.models.sql.where import WhereNode, AND, OR 
    1516from django.db.models.sql.datastructures import Count, Date 
     
    9596        # These are for extensions. The contents are more or less appended 
    9697        # verbatim to the appropriate clause. 
    97         self.extra_select = {}  # Maps col_alias -> col_sql. 
     98        self.extra_select = SortedDict()  # Maps col_alias -> col_sql. 
    9899        self.extra_tables = [] 
    99100        self.extra_where = [] 
     
    365366            aliases = result[:] 
    366367 
    367         # We sort extra_select so that the result columns are in a well-defined 
    368         # order (and thus QuerySet.iterator can extract them correctly). 
    369         extra_select = self.extra_select.items() 
    370         extra_select.sort() 
    371368        result.extend(['(%s) AS %s' % (col, alias) 
    372                 for alias, col in extra_select]) 
     369                for alias, col in self.extra_select.items()]) 
    373370        aliases.extend(self.extra_select.keys()) 
    374371 
     
    762759 
    763760        for child in q_object.children: 
    764             if isinstance(child, tree.Node): 
     761            if isinstance(child, Node): 
    765762                self.where.start_subtree(q_object.connection) 
    766763                self.add_q(child) 
     
    938935            self.distinct = False 
    939936        self.select = [select] 
    940         self.extra_select = {} 
     937        self.extra_select = SortedDict() 
    941938 
    942939    def execute_sql(self, result_type=MULTI): 
  • django/branches/queryset-refactor/docs/db-api.txt

    r6600 r6603  
    821821    subqueries. 
    822822 
     823    **New in Django development version** 
     824    In some rare cases, you might wish to pass parameters to the SQL fragments 
     825    in ``extra(select=...)```. Since the ``params`` attribute is a sequence 
     826    and the ``select`` attribute is a dictionary, some care is required so 
     827    that the parameters are matched up correctly with the extra select pieces. 
     828    Firstly, in this situation, you should use a 
     829    ``django.utils.datastructures.SortedDict`` for the ``select`` value, not 
     830    just a normal Python dictionary. Secondly, make sure that your parameters 
     831    for the ``select`` come first in the list and that you have not passed any 
     832    parameters to an earlier ``extra()`` call for this queryset. 
     833 
     834    This will work:: 
     835 
     836        Blog.objects.extra( 
     837            select=SortedDict(('a', '%s'), ('b', '%s')), 
     838            params=('one', 'two')) 
     839 
     840    ... while this won't:: 
     841 
     842        # Will not work! 
     843        Blog.objects.extra(where=['foo=%s'], params=('bar',)).extra( 
     844            select=SortedDict(('a', '%s'), ('b', '%s')), 
     845            params=('one', 'two')) 
     846 
     847    In the second example, the earlier ``params`` usage will mess up the later 
     848    one. So always put your extra select pieces in the first ``extra()`` call 
     849    if you need to use parameters in them. 
     850 
    823851``where`` / ``tables`` 
    824852    You can define explicit SQL ``WHERE`` clauses -- perhaps to perform 
  • django/branches/queryset-refactor/tests/regressiontests/queries/models.py

    r6600 r6603  
    380380>>> id(q1) == id(q1.all()) 
    381381False 
     382 
     383Bug #2902 
     384Parameters can be given to extra_select, *if* you use a SortedDict. 
     385 
     386(First we need to know which order the keys fall in "naturally" on your system, 
     387so we can put things in the wrong way around from normal. A normal dict would 
     388thus fail.) 
     389>>> from django.utils.datastructures import SortedDict 
     390>>> s = [('a', '%s'), ('b', '%s')] 
     391>>> params = ['one', 'two'] 
     392>>> if {'a': 1, 'b': 2}.keys() == ['a', 'b']: 
     393...     s.reverse() 
     394...     params.reverse() 
     395>>> Item.objects.extra(select=SortedDict(s), params=params).values('a','b')[0] 
     396{'a': u'one', 'b': u'two'} 
    382397"""} 
    383398