Skip to content

Prefetch_related has strange behavior #68

@agateblue

Description

@agateblue

Hi,

I use django-polymorphic for a personal, non-critical project, in which items (Storable) can be stored in workspaces (Workspace).

This project relies heavily on concrete inheritance, and my models all inherit from a base model (using Polymorphic).

Everything works fine but, as always with concrete inheritance, database load is quite high, especially when I want to display a list of Storable, along with their workspaces.
In order to reduce the number of queries, I'm trying to use prefetch_related('workspaces') on Storable queryset. However, while it reduces indeed the number of queries, there is a bug when come the time to display items.

I've set up a test project with the following code.

Models

from django.db import models
from polymorphic import PolymorphicModel


class Base(PolymorphicModel):
    name = models.CharField('name', max_length=255, default=None, blank=True, null=True)


class Storable(Base):
    pass


class Workspace(Base):
    items = models.ManyToManyField(Storable, related_name="workspaces", null=True, blank=True, default = None)

View

from django.views.generic.list import ListView
from test_prefetch_related.models import Storable


class TestPrefetchRelated(ListView):
    model = Storable
    template_name = "test_prefetch_related/test_prefetch_related.html"
    paginate_by = 10

    def get_queryset(self):
        return self.model.objects.all().prefetch_related('workspaces')

Template

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
    {% for item in object_list %}
        <h1>{{ item.name }}</h1>
        <ul>
            {% for w in item.workspaces.all %}
                <li>{{ w.id }} - {{ w.name }}</li>
            {% empty %}
                None
            {% endfor %}
        </ul>
    {% endfor %}
</body>
</html>

Database population

from test_prefetch_related.models import Storable, Workspace

# here is the code I used to populate the database with some data

# create workspaces
w1 = Workspace(name="w1")
w1.save()

w2 = Workspace(name="w2")
w2.save()

w3 = Workspace(name="w3")
w3.save()

# create storables
s1 = Storable(name="s1")
s1.save()
s1.workspaces.add(w1)
s1.save()

s2 = Storable(name="s2")
s2.save()
s2.workspaces.add(w2)
s2.save()

s3 = Storable(name="s3")
s3.save()
s3.workspaces.add(w1, w2, w3)  # this storable get all workpaces
s3.save()

Html output

s1

    1 - w1
    1 - w1

s2

    2 - w2
    2 - w2

s3

    3 - w3

The bug

It's hard to explain (excuse my english ;), but as you can see in output, workspaces are not displayed properly, next to each Storable. Intead, they are grouped on the first item in the queryset with which they are linked.

The expected output would be :

s1

    1 - w1

s2

    2 - w2

s3     

    1 - w1
    2 - w2
    3 - w3

I'm almost sure it is related to polymorphic because the following code using standard django inheritance works as expected.

In polymorphic docs, I did not found any mention of prefetch_related(). Is this behaviour one of the caveats of using concrete inheritance ? Is there anything else I could do to achieve the same result ?

You can download the code I used, if you want to check by yourself : http://seafile.eliotberriot.com/d/aca8f2399a/ (click on ZIP button in top right corner).

Thank you for your help and for this project, apart from that, I'm really happy with it !

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions