18

I have a situation wherein a large number of objects of a particular class are being iterated over, and they take a huge amount of time for processing because I can't pre-select data using select_related.

The class in question goes something like below

from django.contrib.contenttypes.models import ContentType
from django.db import models

class Offer(models.Model):
    ...
    object_id = models.PositiveIntegerField(db_index = True)
    content_type = models.ForeignKey(ContentType, db_index = True)
    content_object = generic.GenericForeignKey('content_type', 'object_id')
    ...

I have tried using select_related like below, but it obviously doesn't work

offerList = Offer.objects.select_related('content_type', "content_object"
    ).filter(content_type=ContentType.objects.get_for_model(SomeObject),
    object_id=someobject.id)

So, how can I use select_related with GenericForeignKey in django?

Anshul Goyal
  • 73,278
  • 37
  • 149
  • 186

1 Answers1

39

It is not select_related what you are looking for. It is prefetch_related, which

supports prefetching of GenericRelation and GenericForeignKey.

Therefore, your base command would be:

Offer.objects.all().prefetch_related('content_object')

Community
  • 1
  • 1
raratiru
  • 8,748
  • 4
  • 73
  • 113
  • what if i need to access via reverse relation...i have a Generic Relation on Offers table and one more from table 'x'...now i am accessing multiple items for x and number of queries for the generic relation are quiet large...any solution? – ronit Nov 13 '18 at 19:39
  • @ronit Actually this is another question of its own because it would help to illustrate the tables and the actual queries. However, you can either use a [`Prefetch`](https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.Prefetch) object with a query that filters and narrows the results, or instead of prefetching you can directly access the objects you need and call [`values()`](https://docs.djangoproject.com/el/2.1/ref/models/querysets/#django.db.models.query.QuerySet.values) which will return a dictionary of the selected attributes, although this might be a long shot. – raratiru Nov 13 '18 at 21:30
  • 1
    @ronit Bear in mind, though, that there are better ways to design the database in order to [avoid the generic relations](https://lukeplant.me.uk/blog/posts/avoid-django-genericforeignkey/)). Actually, I have given up on using them. – raratiru Nov 13 '18 at 23:07
  • why `prefetch_related` doesnt take into query content_object's fields? – Sultan1991 Jan 13 '21 at 10:00
  • @Sultan1991 I am not sure whether you are referring to the complexity of `prefetch_related` which can be remedied using [`Prefetch`](https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#django.contrib.contenttypes.models.ContentType) objects and their `queryset` argument or the complexity of [`ContentTypes`](https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/) which can be solved by refactoring to [avoid them](https://lukeplant.me.uk/blog/posts/avoid-django-genericforeignkey/). – raratiru Jan 14 '21 at 22:45