Commit f4132140 authored by Anssi Kääriäinen's avatar Anssi Kääriäinen
Browse files

[1.5.x] Fixed #19652 -- Fixed .none() regression in related fields

The regression was caused by using .none() when querying for related
models, and the origin field's value was None. This resulted in missing
custom related manager subclass as .none() returns plain QuerySet.

This isn't backport from master, in master .none() correctly preserves
the queryset's class.

Patch provided by Simon Charette, with some minor polish by committer.
parent 54887d68
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -498,7 +498,8 @@ class ForeignRelatedObjectsDescriptor(object):
                    db = self._db or router.db_for_read(self.model, instance=self.instance)
                    qs = super(RelatedManager, self).get_query_set().using(db).filter(**self.core_filters)
                    if getattr(self.instance, attname) is None:
                        return qs.none()
                        # We don't want to use qs.none() here, see #19652
                        return qs.filter(pk__in=[])
                    qs._known_related_objects = {rel_field: {self.instance.pk: self.instance}}
                    return qs

+21 −0
Original line number Diff line number Diff line
@@ -63,3 +63,24 @@ class Car(models.Model):

    def __str__(self):
        return self.name


# Bug #19652
class ObjectQuerySet(models.query.QuerySet):
    pass

class ObjectManager(models.Manager):
    use_for_related_fields = True

    def get_query_set(self):
        return ObjectQuerySet(self.model, using=self._db)


class RelatedObject(models.Model):
    pass


class Object(models.Model):
    related = models.ForeignKey(RelatedObject, related_name='objs')

    objects = ObjectManager()
+12 −1
Original line number Diff line number Diff line
@@ -3,7 +3,8 @@ from __future__ import absolute_import
from django.test import TestCase
from django.utils import six

from .models import Person, Book, Car, PersonManager, PublishedBookManager
from .models import (ObjectQuerySet, RelatedObject, Person, Book, Car, PersonManager,
    PublishedBookManager)


class CustomManagerTests(TestCase):
@@ -72,3 +73,13 @@ class CustomManagerTests(TestCase):
            ],
            lambda c: c.name
        )

    def test_related_manager(self):
        """
        Make sure un-saved object's related managers always return an instance
        of the same class the manager's `get_query_set` returns. Refs #19652.
        """
        rel_qs = RelatedObject().objs.all()
        self.assertIsInstance(rel_qs, ObjectQuerySet)
        with self.assertNumQueries(0):
            self.assertFalse(rel_qs.exists())