Commit 806d898b authored by Justin Bronn's avatar Justin Bronn
Browse files

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

[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
parent 866574a8
Loading
Loading
Loading
Loading
+18 −16
Original line number Diff line number Diff line
@@ -66,7 +66,7 @@ class GeoQuery(sql.Query):
            # This loop customized for GeoQuery.
            for col, field in izip(self.select, self.select_fields):
                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:
                        c_alias = 'Col%d' % len(col_aliases)
                        result.append('%s AS %s' % (r, c_alias))
@@ -89,7 +89,7 @@ class GeoQuery(sql.Query):
        # This loop customized for GeoQuery.
        if not self.aggregate:
            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:
                    c_alias = 'Col%d' % len(col_aliases)
                    result.append('%s AS %s' % (r, c_alias))
@@ -219,19 +219,20 @@ class GeoQuery(sql.Query):
            sel_fmt = sel_fmt % self.custom_select[alias]
        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
        if any custom selection SQL is needed for the column  The `alias`
        keyword may be used to manually specify the database table where
        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)
        if fld in self.custom_select:
            field_sel = sel_fmt % self.custom_select[fld]
        sel_fmt = self.get_select_format(field)
        if field in self.custom_select:
            field_sel = sel_fmt % self.custom_select[field]
        else:
            field_sel = sel_fmt % self._field_column(fld, alias)
            field_sel = sel_fmt % self._field_column(field, alias, column)
        return field_sel

    def get_select_format(self, fld):
@@ -293,17 +294,18 @@ class GeoQuery(sql.Query):
        else:
            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.
        The table and column are returned (quoted) in the proper format, e.g.,
        `"geoapp_city"."point"`.  If `table_alias` is not specified, the
        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
        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):
        """
+20 −0
Original line number Diff line number Diff line
@@ -95,6 +95,26 @@ class RelatedGeoModelTest(unittest.TestCase):
        # Regression test for #9752.
        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.
        
def suite():