mirror of
https://github.com/django/django.git
synced 2025-07-19 00:59:17 +00:00
[1.0.X] Fixed #10757 -- Fixed improper selection of primary keys across 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
This commit is contained in:
parent
866574a854
commit
806d898bbf
@ -66,7 +66,7 @@ class GeoQuery(sql.Query):
|
|||||||
# This loop customized for GeoQuery.
|
# This loop customized for GeoQuery.
|
||||||
for col, field in izip(self.select, self.select_fields):
|
for col, field in izip(self.select, self.select_fields):
|
||||||
if isinstance(col, (list, tuple)):
|
if isinstance(col, (list, tuple)):
|
||||||
r = self.get_field_select(field, col[0])
|
r = self.get_field_select(field, col[0], col[1])
|
||||||
if with_aliases and col[1] in col_aliases:
|
if with_aliases and col[1] in col_aliases:
|
||||||
c_alias = 'Col%d' % len(col_aliases)
|
c_alias = 'Col%d' % len(col_aliases)
|
||||||
result.append('%s AS %s' % (r, c_alias))
|
result.append('%s AS %s' % (r, c_alias))
|
||||||
@ -89,7 +89,7 @@ class GeoQuery(sql.Query):
|
|||||||
# This loop customized for GeoQuery.
|
# This loop customized for GeoQuery.
|
||||||
if not self.aggregate:
|
if not self.aggregate:
|
||||||
for (table, col), field in izip(self.related_select_cols, self.related_select_fields):
|
for (table, col), field in izip(self.related_select_cols, self.related_select_fields):
|
||||||
r = self.get_field_select(field, table)
|
r = self.get_field_select(field, table, col)
|
||||||
if with_aliases and col in col_aliases:
|
if with_aliases and col in col_aliases:
|
||||||
c_alias = 'Col%d' % len(col_aliases)
|
c_alias = 'Col%d' % len(col_aliases)
|
||||||
result.append('%s AS %s' % (r, c_alias))
|
result.append('%s AS %s' % (r, c_alias))
|
||||||
@ -219,19 +219,20 @@ class GeoQuery(sql.Query):
|
|||||||
sel_fmt = sel_fmt % self.custom_select[alias]
|
sel_fmt = sel_fmt % self.custom_select[alias]
|
||||||
return sel_fmt
|
return sel_fmt
|
||||||
|
|
||||||
def get_field_select(self, fld, alias=None):
|
def get_field_select(self, field, alias=None, column=None):
|
||||||
"""
|
"""
|
||||||
Returns the SELECT SQL string for the given field. Figures out
|
Returns the SELECT SQL string for the given field. Figures out
|
||||||
if any custom selection SQL is needed for the column The `alias`
|
if any custom selection SQL is needed for the column The `alias`
|
||||||
keyword may be used to manually specify the database table where
|
keyword may be used to manually specify the database table where
|
||||||
the column exists, if not in the model associated with this
|
the column exists, if not in the model associated with this
|
||||||
`GeoQuery`.
|
`GeoQuery`. Similarly, `column` may be used to specify the exact
|
||||||
|
column name, rather than using the `column` attribute on `field`.
|
||||||
"""
|
"""
|
||||||
sel_fmt = self.get_select_format(fld)
|
sel_fmt = self.get_select_format(field)
|
||||||
if fld in self.custom_select:
|
if field in self.custom_select:
|
||||||
field_sel = sel_fmt % self.custom_select[fld]
|
field_sel = sel_fmt % self.custom_select[field]
|
||||||
else:
|
else:
|
||||||
field_sel = sel_fmt % self._field_column(fld, alias)
|
field_sel = sel_fmt % self._field_column(field, alias, column)
|
||||||
return field_sel
|
return field_sel
|
||||||
|
|
||||||
def get_select_format(self, fld):
|
def get_select_format(self, fld):
|
||||||
@ -293,17 +294,18 @@ class GeoQuery(sql.Query):
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _field_column(self, field, table_alias=None):
|
def _field_column(self, field, table_alias=None, column=None):
|
||||||
"""
|
"""
|
||||||
Helper function that returns the database column for the given field.
|
Helper function that returns the database column for the given field.
|
||||||
The table and column are returned (quoted) in the proper format, e.g.,
|
The table and column are returned (quoted) in the proper format, e.g.,
|
||||||
`"geoapp_city"."point"`. If `table_alias` is not specified, the
|
`"geoapp_city"."point"`. If `table_alias` is not specified, the
|
||||||
database table associated with the model of this `GeoQuery` will be
|
database table associated with the model of this `GeoQuery` will be
|
||||||
used.
|
used. If `column` is specified, it will be used instead of the value
|
||||||
|
in `field.column`.
|
||||||
"""
|
"""
|
||||||
if table_alias is None: table_alias = self.model._meta.db_table
|
if table_alias is None: table_alias = self.model._meta.db_table
|
||||||
return "%s.%s" % (self.quote_name_unless_alias(table_alias),
|
return "%s.%s" % (self.quote_name_unless_alias(table_alias),
|
||||||
self.connection.ops.quote_name(field.column))
|
self.connection.ops.quote_name(column or field.column))
|
||||||
|
|
||||||
def _geo_field(self, field_name=None):
|
def _geo_field(self, field_name=None):
|
||||||
"""
|
"""
|
||||||
|
@ -95,6 +95,26 @@ class RelatedGeoModelTest(unittest.TestCase):
|
|||||||
# Regression test for #9752.
|
# Regression test for #9752.
|
||||||
l = list(DirectoryEntry.objects.all().select_related())
|
l = list(DirectoryEntry.objects.all().select_related())
|
||||||
|
|
||||||
|
def test09_pk_relations(self):
|
||||||
|
"Ensuring correct primary key column is selected across relations. See #10757."
|
||||||
|
# Adding two more cities, but this time making sure that their location
|
||||||
|
# ID values do not match their City ID values.
|
||||||
|
loc1 = Location.objects.create(point='POINT (-95.363151 29.763374)')
|
||||||
|
loc2 = Location.objects.create(point='POINT (-96.801611 32.782057)')
|
||||||
|
dallas = City.objects.create(name='Dallas', location=loc2)
|
||||||
|
houston = City.objects.create(name='Houston', location=loc1)
|
||||||
|
|
||||||
|
# The expected ID values -- notice the last two location IDs
|
||||||
|
# are out of order. We want to make sure that the related
|
||||||
|
# location ID column is selected instead of ID column for
|
||||||
|
# the city.
|
||||||
|
city_ids = (1, 2, 3, 4, 5)
|
||||||
|
loc_ids = (1, 2, 3, 5, 4)
|
||||||
|
ids_qs = City.objects.order_by('id').values('id', 'location__id')
|
||||||
|
for val_dict, c_id, l_id in zip(ids_qs, city_ids, loc_ids):
|
||||||
|
self.assertEqual(val_dict['id'], c_id)
|
||||||
|
self.assertEqual(val_dict['location__id'], l_id)
|
||||||
|
|
||||||
# TODO: Related tests for KML, GML, and distance lookups.
|
# TODO: Related tests for KML, GML, and distance lookups.
|
||||||
|
|
||||||
def suite():
|
def suite():
|
||||||
|
Loading…
x
Reference in New Issue
Block a user