1
0
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:
Justin Bronn 2009-04-07 21:33:43 +00:00
parent 866574a854
commit 806d898bbf
2 changed files with 38 additions and 16 deletions

View File

@ -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):
""" """

View File

@ -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():