39

Is there a way of filtering prefetched objects? I need to get the latest() of the prefetched objects but prefetch_related doesn't work if you use latest because the query is changed?

The example here does what I need but I was hoping there's a simpler workaround...

https://github.com/ionelmc/django-prefetch#example

alan
  • 4,247
  • 7
  • 37
  • 49

3 Answers3

31

As of Django 1.7, filtering prefetched objects is possible. See this SO answer, and the Django documentation.

weAreStarsDust
  • 2,634
  • 3
  • 10
  • 22
Webthusiast
  • 986
  • 10
  • 16
  • The Django documentation currently seems to suggest otherwise. It says the following, and goes into a bit more depth than this: "Remember that, as always with QuerySets, any subsequent chained methods which imply a different database query will ignore previously cached results, and retrieve data using a fresh database query." It specifically says that calling a method on a prefetched set of data "in fact it hurts performance, since you have done a database query that you haven’t used. So use this feature with caution!" – Rik Schoonbeek Nov 01 '22 at 10:52
  • You can avoid the additional filter by making use of the `Prefetch` object – James Lin Aug 15 '23 at 23:44
7

It is very simple method which is hardly comparable with those app, but hope you will find it useful:

class Author(models.Model):
    name = models.CharField(max_length=100)

    def latest_book(self):
        return max(self.book_set.all(), key=lambda book: book.created)

authors = Author.objects.prefetch_related('book_set')
authors[0].latest_book() #  what you wanted
jasisz
  • 1,288
  • 8
  • 9
  • 1
    I tested this and it seems to generate the same queries as the naive loop... I don't think you can use select_related on a reverse relation – alan Sep 27 '12 at 12:53
  • 2
    I am sorry - of course it should be prefetch_related (I edited my answer). Using this hole set with all() is prefetched and iterating it shouldn't hit database. – jasisz Sep 27 '12 at 16:38
  • How can I filter using lambda? – Anuj TBE May 12 '20 at 11:11
-1

Yes, it can be done in this way :

authors=Author.objects.prefetch_related('book_set')

If you want to filter by an attribute(name) present in Author model you can simply filter it by writing:

authors.filter(name='your_value')

But if you want to apply filter on the Books model you have to write the following way:

authors.filter(book__created__gt='your_date')

This will filter all the books that have create date(created attribute in the Book module) greater than your date.

Manasvi Batra
  • 384
  • 2
  • 14