Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django queryset to return first of each item in foreign key based on date

need to get a queryset with the first book (by a date field) for each author (related to by foreign key) ...is there a Django ORM way to do this (without custom SQL preferred but acceptable)

*Edit: Please note that an answer that works using only a modern open source backend like Postgresql is acceptable ..still ORM based solution preferred over pure custom sql query)

Models
class Book(Model):
  date = Datefield()
  author = ForeignKey(Author)

class Author(Model):
  name = CharField()


Book.objects.filter(??)
like image 235
eskhool Avatar asked Jan 09 '13 12:01

eskhool


1 Answers

If you use PostgreSQL or another DB backend with support for DISTINCT ON there is a nice solution:

Books.objects.order_by('author', '-date').distinct('author')

Otherwise I don't know a solution with only one query. But you can try this:

from django.db.models import Q, Max
import operator

books = Book.objects.values('author_id').annotate(max_date=Max('date'))
filters = reduce(operator.or_, [(Q(author_id=b['author_id']) &
    Q(date=b['max_date'])) for b in books])
queryset = Books.objects.filter(filters)

With the combination of .values() and .annotate() we group by the author and annotate the latest date of all books from that author. But the result is a dict and not a queryset. Then we build a SQL statement like WHERE author_id=X1 AND date=Y1 OR author_id=X2 AND date=Y2.... Now the second query is easy.

like image 192
Hannes Avatar answered Oct 13 '22 07:10

Hannes