Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

[1.0.X] Fixed #10757 -- Fixed improper selection of primary keys acro…

…ss relations when using `GeoManager.values`. Thanks, David Gouldin for ticket and initial patch.

Backport of r10434 from trunk.


git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.0.X@10437 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 806d898bbf7cc0f067674f4c112ab62786a3ce57 1 parent 866574a
Justin Bronn authored
34  django/contrib/gis/db/models/sql/query.py
@@ -66,7 +66,7 @@ def get_columns(self, with_aliases=False):
66 66
             # This loop customized for GeoQuery.
67 67
             for col, field in izip(self.select, self.select_fields):
68 68
                 if isinstance(col, (list, tuple)):
69  
-                    r = self.get_field_select(field, col[0])
  69
+                    r = self.get_field_select(field, col[0], col[1])
70 70
                     if with_aliases and col[1] in col_aliases:
71 71
                         c_alias = 'Col%d' % len(col_aliases)
72 72
                         result.append('%s AS %s' % (r, c_alias))
@@ -89,7 +89,7 @@ def get_columns(self, with_aliases=False):
89 89
         # This loop customized for GeoQuery.
90 90
         if not self.aggregate:
91 91
             for (table, col), field in izip(self.related_select_cols, self.related_select_fields):
92  
-                r = self.get_field_select(field, table)
  92
+                r = self.get_field_select(field, table, col)
93 93
                 if with_aliases and col in col_aliases:
94 94
                     c_alias = 'Col%d' % len(col_aliases)
95 95
                     result.append('%s AS %s' % (r, c_alias))
@@ -219,19 +219,20 @@ def get_extra_select_format(self, alias):
219 219
             sel_fmt = sel_fmt % self.custom_select[alias]
220 220
         return sel_fmt
221 221
 
222  
-    def get_field_select(self, fld, alias=None):
  222
+    def get_field_select(self, field, alias=None, column=None):
223 223
         """
224 224
         Returns the SELECT SQL string for the given field.  Figures out
225  
-        if any custom selection SQL is needed for the column  The `alias` 
226  
-        keyword may be used to manually specify the database table where 
227  
-        the column exists, if not in the model associated with this 
228  
-        `GeoQuery`.
  225
+        if any custom selection SQL is needed for the column  The `alias`
  226
+        keyword may be used to manually specify the database table where
  227
+        the column exists, if not in the model associated with this
  228
+        `GeoQuery`.  Similarly, `column` may be used to specify the exact
  229
+        column name, rather than using the `column` attribute on `field`.
229 230
         """
230  
-        sel_fmt = self.get_select_format(fld)
231  
-        if fld in self.custom_select:
232  
-            field_sel = sel_fmt % self.custom_select[fld]
  231
+        sel_fmt = self.get_select_format(field)
  232
+        if field in self.custom_select:
  233
+            field_sel = sel_fmt % self.custom_select[field]
233 234
         else:
234  
-            field_sel = sel_fmt % self._field_column(fld, alias)
  235
+            field_sel = sel_fmt % self._field_column(field, alias, column)
235 236
         return field_sel
236 237
 
237 238
     def get_select_format(self, fld):
@@ -293,17 +294,18 @@ def _check_geo_field(self, model, name_param):
293 294
         else:
294 295
             return False
295 296
 
296  
-    def _field_column(self, field, table_alias=None):
  297
+    def _field_column(self, field, table_alias=None, column=None):
297 298
         """
298 299
         Helper function that returns the database column for the given field.
299 300
         The table and column are returned (quoted) in the proper format, e.g.,
300  
-        `"geoapp_city"."point"`.  If `table_alias` is not specified, the 
  301
+        `"geoapp_city"."point"`.  If `table_alias` is not specified, the
301 302
         database table associated with the model of this `GeoQuery` will be
302  
-        used.
  303
+        used.  If `column` is specified, it will be used instead of the value
  304
+        in `field.column`.
303 305
         """
304 306
         if table_alias is None: table_alias = self.model._meta.db_table
305  
-        return "%s.%s" % (self.quote_name_unless_alias(table_alias), 
306  
-                          self.connection.ops.quote_name(field.column))
  307
+        return "%s.%s" % (self.quote_name_unless_alias(table_alias),
  308
+                          self.connection.ops.quote_name(column or field.column))
307 309
 
308 310
     def _geo_field(self, field_name=None):
309 311
         """
20  django/contrib/gis/tests/relatedapp/tests.py
@@ -95,6 +95,26 @@ def test05_select_related_fk_to_subclass(self):
95 95
         # Regression test for #9752.
96 96
         l = list(DirectoryEntry.objects.all().select_related())
97 97
 
  98
+    def test09_pk_relations(self):
  99
+        "Ensuring correct primary key column is selected across relations. See #10757."
  100
+        # Adding two more cities, but this time making sure that their location
  101
+        # ID values do not match their City ID values.
  102
+        loc1 = Location.objects.create(point='POINT (-95.363151 29.763374)')
  103
+        loc2 = Location.objects.create(point='POINT (-96.801611 32.782057)')
  104
+        dallas = City.objects.create(name='Dallas', location=loc2)
  105
+        houston = City.objects.create(name='Houston', location=loc1)
  106
+
  107
+        # The expected ID values -- notice the last two location IDs
  108
+        # are out of order.  We want to make sure that the related
  109
+        # location ID column is selected instead of ID column for
  110
+        # the city.
  111
+        city_ids = (1, 2, 3, 4, 5)
  112
+        loc_ids = (1, 2, 3, 5, 4)
  113
+        ids_qs = City.objects.order_by('id').values('id', 'location__id')
  114
+        for val_dict, c_id, l_id in zip(ids_qs, city_ids, loc_ids):
  115
+            self.assertEqual(val_dict['id'], c_id)
  116
+            self.assertEqual(val_dict['location__id'], l_id)
  117
+
98 118
     # TODO: Related tests for KML, GML, and distance lookups.
99 119
         
100 120
 def suite():

0 notes on commit 806d898

Please sign in to comment.
Something went wrong with that request. Please try again.