Django

Code

Ticket #7126: gis_select_related.diff

File gis_select_related.diff, 4.5 kB (added by jbronn, 7 months ago)

Fix for selection of geometry columns when using select_related on MySQL/Oracle.

  • django/contrib/gis/db/models/query.py

    old new  
     1from itertools import izip 
    12from django.core.exceptions import ImproperlyConfigured 
    23from django.db import connection 
    34from django.db.models.query import sql, QuerySet, Q 
     
    5354        obj.ewkt = self.ewkt 
    5455        return obj 
    5556 
     57    def get_columns(self, with_aliases=False): 
     58        """ 
     59        Return the list of columns to use in the select statement. If no 
     60        columns have been specified, returns all columns relating to fields in 
     61        the model. 
     62 
     63        If 'with_aliases' is true, any column names that are duplicated 
     64        (without the table names) are given unique aliases. This is needed in 
     65        some cases to avoid ambiguitity with nested queries. 
     66 
     67        This routine is overridden from Query to handle customized selection of  
     68        geometry columns. 
     69        """ 
     70        qn = self.quote_name_unless_alias 
     71        result = ['(%s) AS %s' % (col, alias) for alias, col in self.extra_select.iteritems()] 
     72        aliases = set(self.extra_select.keys()) 
     73        if with_aliases: 
     74            col_aliases = aliases.copy() 
     75        else: 
     76            col_aliases = set() 
     77        if self.select: 
     78            for col, field in izip(self.select, self.select_fields): 
     79                if isinstance(col, (list, tuple)): 
     80                    # This part customized for GeoQuery. 
     81                    sel_fmt = self.get_select_format(field) 
     82                    r = '%s.%s' % (qn(col[0]), qn(col[1])) 
     83                    r = sel_fmt % r 
     84                    if with_aliases and col[1] in col_aliases: 
     85                        c_alias = 'Col%d' % len(col_aliases) 
     86                        result.append('%s AS %s' % (r, c_alias)) 
     87                        aliases.add(c_alias) 
     88                        col_aliases.add(c_alias) 
     89                    else: 
     90                        result.append(r) 
     91                        aliases.add(r) 
     92                        col_aliases.add(col[1]) 
     93                else: 
     94                    result.append(col.as_sql(quote_func=qn)) 
     95                    if hasattr(col, 'alias'): 
     96                        aliases.add(col.alias) 
     97                        col_aliases.add(col.alias) 
     98        elif self.default_cols: 
     99            cols, new_aliases = self.get_default_columns(with_aliases, 
     100                    col_aliases) 
     101            result.extend(cols) 
     102            aliases.update(new_aliases) 
     103 
     104        for i in xrange(len(self.related_select_cols)): 
     105            table, col = self.related_select_cols[i] 
     106            field = self.related_select_fields[i] 
     107 
     108            # This part customized for GeoQuery. 
     109            sel_fmt = self.get_select_format(field) 
     110            r = '%s.%s' % (qn(table), qn(col)) 
     111            r = sel_fmt % r 
     112 
     113            if with_aliases and col in col_aliases: 
     114                c_alias = 'Col%d' % len(col_aliases) 
     115                result.append('%s AS %s' % (r, c_alias)) 
     116                aliases.add(c_alias) 
     117                col_aliases.add(c_alias) 
     118            else: 
     119                result.append(r) 
     120                aliases.add(r) 
     121                col_aliases.add(col) 
     122 
     123        self._select_aliases = aliases 
     124        return result 
     125 
    56126    def get_default_columns(self, with_aliases=False, col_aliases=None): 
    57127        """ 
    58128        Computes the default columns for selecting every field in the base 
     
    79149                        root_pk, model._meta.pk.column)) 
    80150                seen[model] = alias 
    81151 
    82             # This part of the function is customized for GeoQuerySet. We 
     152            # This part of the function is customized for GeoQuery. We 
    83153            # see if there was any custom selection specified in the 
    84154            # dictionary, and set up the selection format appropriately. 
    85155            sel_fmt = self.get_select_format(field) 
     
    229299        extent_sql = '%s(%s)' % (EXTENT, geo_col) 
    230300 
    231301        self.query.select = [GeomSQL(extent_sql)] 
     302        self.query.select_fields = [None] 
    232303        try: 
    233304            esql, params = self.query.as_sql() 
    234305        except sql.datastructures.EmptyResultSet: 
     
    365436 
    366437        # Only want the union SQL to be selected. 
    367438        self.query.select = [GeomSQL(union_sql)] 
     439        self.query.select_fields = [GeometryField] 
    368440        try: 
    369441            usql, params = self.query.as_sql() 
    370442        except sql.datastructures.EmptyResultSet: