Skip to content

Filtering on related manager when using prefetch_related with explicit queryset on a ClusterableModel returns wrong results #170

@maqnius

Description

@maqnius

When applying prefetch_related with a given queryset , the results of the related manager on the returned instances do return the wrong results if .filter(..) is applied instead of the (cached) .all() query.

Probably anything than .all() will return wrong results.

Unfortunately I could not really figure out where the bug exactly is located, because I'm too unfamiliar with this part of the django code base, but I guess it is related to the modelcluster.fields.ChildObjectsDescriptor.

This issue is related to and probably a duplicate of #103, but I narrowed down the steps to reproduce the bug and I hope this will get more attention then.

Steps to Reproduce

Models

from django.db import models
from modelcluster.models import ClusterableModel
from modelcluster.fields import ParentalKey


class Parent(ClusterableModel):
    pass


class Child(models.Model):
    parent = ParentalKey(Parent, related_name="children", on_delete=models.PROTECT)

Test

class TestPrefetch(TestCase):
    def setUp(self):
        # Create parents
        parent_1 = Parent.objects.create()
        parent_2 = Parent.objects.create()

        # Create a children for each parent
        Child.objects.create(parent=parent_1)
        Child.objects.create(parent=parent_2)

    def test_prefetch(self):
        parents = Parent.objects.prefetch_related(
            Prefetch("children", queryset=Child.objects.all())
        )

        # Select an instance
        parent_1 = parents[0]

        self.assertListEqual(
            list(parent_1.children.filter()),
            list(parent_1.children.all()),
        )

Expected Result

parent_1.children.filter() and parent_1.children.all() should return the same queryset containing only the children of the instance parent_1.

Actual Result

parent_1.children.filter() returns all children in the database, also the one related to parent_2 only. Any further filtering is applied to this queryset and will yield wrong results.

AssertionError: Lists differ: [<Child: Child object (1)>, <Child: Child object (2)>] != [<Child: Child object (1)>]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions