I have Book
and Review
models in my app, Review
has foreign key field pointing to Book
.
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from datetime import datetime
class Book(models.Model):
title = models.CharField(max_length=300, null=False, blank=False)
category = models.CharField(max_length=40, blank=True)
class Review(models.Model):
reviewer = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
book = models.ForeignKey(Book, on_delete=models.CASCADE, null=False)
date_last_modified = models.DateTimeField(null=True)
is_closed = models.BooleanField(default=False)
Now, by applying some filters I have a QuerySet
of Books
(eg. books from certain category
).
books_qs = Book.objects.filter(category='World War II')
Having this QuerySet
I want to find most recent Review
with is_closed=True
for each Book
up to any given date. The simplest solution is of course:
desired_date = datetime(2018, 2, 12)
reviews = []
for book in books_qs:
try:
latest = book.review_set.filter(date_last_modified__lt=desired_date, is_closed=True).latest('date_last_modified')
except Book.DoesNotExist: # latest() throws this exception if Book has no reviews
continue
else:
reviews.append(latest)
Is there a way to improve this to get all Reviews
in one query, instead of doing it multiple times in a loop for each Book
?
Another way of phrasing your problem is that you'd like to filter on all reviews whose book is categorized by "World War II", was modified before desired_date
, and is_closed
and group by book and take the most recent review.
So we'll filter our reviews by exactly those criteria. We'll then order the queryset by book
and date_last_modified
so that when we take distinct values on book
, they'll be sorted by the field we want to take the "first" of in each group.
Review.objects.filter(
date_last_modified__lt=desired_date, is_closed=True,
book__category='World War II',
).order_by("book", "-date_last_modified").distinct("book")
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.