5

I have a plain Django model that has a ForeignKey relation to a django-polymorphic model.

Let's call the first PlainModel that has a content ForeignKey field to a polymorphic Content model with subtypes Video and Audio (simplified example).

Now I want to query for all PlainModel instances that refer to a Video.

Problem is all the docs I find are about filtering directly via the polymorphic model itself. So in this example something like Content.objects.instance_of(Video). But I need PlainModel's, so it would need to look something like PlainModel.objects.filter(content__instance_of=Video). I tried a bunch of variations but I cannot find anything that works.

In the docs they use Q(instance_of=ModelB), but this doesn't work on the relation as Q(content__instance_of=ModelB). It gives an error like 'Cannot query "x": Must be "y" instance.' even with the translation call, I guess because the PlainModel is not polymorphic aware.

I have a temporary hack that directly filters on the polymorphic_ctype field using regular django filter like PlainModel.objects.filter(content__polymorphic_ctype_id=my_content_type_id), but this doesn't handle subclasses. Eg: ExtendedVideo would not be found when looking for Video, because it would have a different ContentType id.

I could go solve this and keep a list of allowed subtypes or parse the type hierarchy to get more content types for the filter but that seems to duplicating functionality from django-polymorphic.

Bartvds
  • 3,340
  • 5
  • 30
  • 42

2 Answers2

1

You can do this by first getting all the PlainModel instances that have a Video subtype, and then querying for the foreign key relationships that are in that queryset:

content_videos = Content.objects.instance_of(Video)
plain_model_videos = PlainModel.objects.filter(content__in=content_videos)

Please see the docs for reference.

YPCrumble
  • 26,610
  • 23
  • 107
  • 172
  • Good idea, but I'll have to look at the SQL this executes to see if this is acceptable. IIRC there was something about querysets as `__in` clause. – Bartvds Oct 13 '16 at 12:00
  • @Bartvds this isn't specific to Django Polymorphic because we know the first query gets you the id's you need for the second query. Updated my answer with reference to the SQL query in the docs. – YPCrumble Oct 13 '16 at 12:17
  • Sure, but I was hoping for a solution that uses JOIN's (either via Django Polymorphic or directly through the ORM); as the docs note sub-queries aren't so great performance wise, especially in larger tables like ours. But I think we need to benchmark and see if this is acceptable already. – Bartvds Oct 13 '16 at 13:26
1

video plain_models:

PlainModel.objects.filter(content__video__isnull=False)

other plain_models, except video:

PlainModel.objects.filter(content__video__isnull=True)
thinker3
  • 12,771
  • 5
  • 30
  • 36