7

I'm displaying 7 random objects on a home page. For that I use solution based on this answer:

class ProductManager(models.Manager):
    def random(self, n_products, filter={}, select_related=None):
        n_products_total = self.filter(**filter).count()
        if n_products_total == 0:
            return []
        r = [
            self.random_impl(n_products_total, filter, select_related)
            for i in range(n_products)
        ]
        return [p for p in r if p is not None]

    def random_impl(self, n_products, filter, select_related=None):
        random_index = randint(0, n_products - 1)
        try:
            return self.filter(**filter) \
                .select_related(select_related)[random_index]
        except IndexError:
            return None

random_products = Product.objects.random(
    7, filter={'enabled': True}, select_related='category'
)

If I pass prefetch_related=Prefetch('productphoto_set', queryset=ProductPhoto.objects.order_by('pk')) to random_impl method, it prefetches 1 photo at a time for each product. Which is not surprising. Can I prefetch related objects manually after products has already been fetched?

djvg
  • 11,722
  • 5
  • 72
  • 103
x-yuri
  • 16,722
  • 15
  • 114
  • 161

1 Answers1

8

To my surprise, there's a legal way. Documented, that is. You just need to add:

prefetch_related_objects(
    random_products, 
    Prefetch('productphoto_set', queryset=ProductPhoto.objects.order_by('pk')),
)
djvg
  • 11,722
  • 5
  • 72
  • 103
x-yuri
  • 16,722
  • 15
  • 114
  • 161