Commit 67732a9b authored by Tim Graham's avatar Tim Graham
Browse files

Fixed #24687 -- Added select_related() validation for nested non-relational fields.

The removed test was added in the original select_related() validation
patch (45d4e43d2d25b902e3821b612209afa951a8bcb8), but there doesn't
seem to be any reason for it.

Thanks Claude Paroz for help and review.
parent 5171f56f
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ from django.contrib.gis.db.models.sql import (
from django.contrib.gis.geometry.backend import Geometry
from django.contrib.gis.measure import Area, Distance
from django.db import connections
from django.db.models.constants import LOOKUP_SEP
from django.db.models.expressions import RawSQL
from django.db.models.fields import Field
from django.db.models.query import QuerySet
@@ -675,9 +676,10 @@ class GeoQuerySet(QuerySet):
        if geo_field not in opts.fields:
            # Is this operation going to be on a related geographic field?
            # If so, it'll have to be added to the select related information
            # (e.g., if 'location__point' was given as the field name).
            # (e.g., if 'location__point' was given as the field name, then
            # chop the non-relational field and add select_related('location')).
            # Note: the operation really is defined as "must add select related!"
            self.query.add_select_related([field_name])
            self.query.add_select_related([field_name.rsplit(LOOKUP_SEP, 1)[0]])
            # Call pre_sql_setup() so that compiler.select gets populated.
            compiler.pre_sql_setup()
            for col, _, _ in compiler.select:
+1 −1
Original line number Diff line number Diff line
@@ -673,7 +673,7 @@ class SQLCompiler(object):
                if not f.is_relation:
                    # If a non-related field is used like a relation,
                    # or if a single non-relational field is given.
                    if next or (cur_depth == 1 and f.name in requested):
                    if next or f.name in requested:
                        raise FieldError(
                            "Non-relational field given in select_related: '%s'. "
                            "Choices are: %s" % (
+17 −0
Original line number Diff line number Diff line
@@ -217,6 +217,23 @@ Database backend API

* ...

``select_related()`` prohibits non-relational fields for nested relations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Django 1.8 added validation for non-relational fields in ``select_related()``::

    >>> Book.objects.select_related('title')
    Traceback (most recent call last):
    ...
    FieldError: Non-relational field given in select_related: 'title'

But it didn't prohibit nested non-relation fields as it does now::

    >>> Book.objects.select_related('author__name')
    Traceback (most recent call last):
    ...
    FieldError: Non-relational field given in select_related: 'name'

Miscellaneous
~~~~~~~~~~~~~

+1 −1
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ class ChildAdmin(admin.ModelAdmin):
    list_filter = ['parent', 'age']

    def get_queryset(self, request):
        return super(ChildAdmin, self).get_queryset(request).select_related("parent__name")
        return super(ChildAdmin, self).get_queryset(request).select_related("parent")


class CustomPaginationAdmin(ChildAdmin):
+1 −3
Original line number Diff line number Diff line
@@ -75,9 +75,7 @@ class ChangeListTests(TestCase):
            request, Child,
            *get_changelist_args(m, list_select_related=m.get_list_select_related(request))
        )
        self.assertEqual(cl.queryset.query.select_related, {
            'parent': {'name': {}}
        })
        self.assertEqual(cl.queryset.query.select_related, {'parent': {}})

    def test_select_related_as_tuple(self):
        ia = InvitationAdmin(Invitation, custom_site)
Loading