Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GenericPrefetch does not work correctly with Polymorphic Models #613

Open
vladjkeeee13 opened this issue Jul 23, 2024 · 1 comment
Open

Comments

@vladjkeeee13
Copy link

vladjkeeee13 commented Jul 23, 2024

Description

I am encountering an issue when using GenericPrefetch with PolymorphicModel. The content_object attribute is None when trying to prefetch related objects.

Environment

  • Django version: 5.0.7
  • django-polymorphic version: 3.1.0
  • Python version: 3.10

Steps to Reproduce

  1. Create a polymorphic model with a custom manager.
  2. Use GenericPrefetch to prefetch related objects.
  3. Iterate over the related objects to access the content_object.

Code Example

# models.py
from django.db import models
from polymorphic.models import PolymorphicModel
from polymorphic.manager import PolymorphicManager

class Bookmark(PolymorphicModel):
    url = models.URLField()
    tags = GenericRelation(TaggedItem)
    objects = CustomManager()

class TaggedItem(models.Model):
    tag = models.SlugField()
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey("content_type", "object_id")

# custom_manager.py
from polymorphic.query import PolymorphicQuerySet

class CustomManager(PolymorphicManager):
    def get_queryset(self) -> PolymorphicQuerySet:
        return (
            super()
            .get_queryset()
            .annotate(...)
        )


# views.py
from django.db.models import Prefetch
from polymorphic.query import PolymorphicQuerySet

def get_queryset():
    return TaggedItem.objects.prefetch_related(
        GenericPrefetch(
            lookup='content_object',
            querysets=[
                Bookmark.objects.all(),
            ],
        ),
    )

# Accessing the `content_object`
for tag in tags:
    print(tag.content_object)  # This is None

Expected Behavior

The content_object should be correctly populated when using GenericPrefetch.

Actual Behavior

The content_object is None when using GenericPrefetch.

Additional Information

If GenericPrefetch is removed, the content_object is correctly populated. Additionally, if PolymorphicModel and PolymorphicManager are removed from the model, the issue does not occur. It seems that the combination of PolymorphicModel and GenericPrefetch might be causing the issue.

Request

Could you provide guidance on how to correctly use GenericPrefetch with PolymorphicModel or suggest any workarounds? Thank you!

@DeD1rk
Copy link

DeD1rk commented Nov 4, 2024

@vladjkeeee13 I'm running into the same issue. Additionally, of course the following does work a little better, but doesn't return the child models:

SomeModel.objects.all().prefetch_related(
    GenericPrefetch("content_object", [SomePolymorphicModel.objects.all().non_polymorphic()])
)

An ugly workaround can be to manually prefetch the polymorphic objects, something like:

objects = SomeModel.objects.all()
polymorphic_objects = {obj.pk: obj for obj in SomePolymorphicModel.objects.filter(pk__in=[o.object_pk for o in objects])}
for obj in objects:
   obj._object = polymorphic_objects.get(int(obj.object_pk))

I would also love a proper implementation for this though, as my workaround requires separately handling each polymorphic model(-tree) that might be in the generic relation (which is exactly what generic relations are meant to avoid).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants