如何在Django中过滤外键关联对象?特定用户当前借阅书籍查询异常的解决方案
解决Django中查询书籍最新借阅记录的问题
看来你遇到的问题是原查询会返回所有被目标用户借过的书籍,而不是当前(最新)在借的,同时你还需要获取每本书的最新借阅人信息。让我一步步帮你解决:
为什么原查询不生效?
你的语句 Book.objects.filter(lends__person__username__iexact="Antony") 会匹配所有关联过Antony的借阅记录的书籍——也就是说,只要Antony曾经借过某本书,不管是不是现在在借,这本书都会被返回。而且如果同一本书被借多次,还会返回重复的Book实例,完全不符合你要的「当前借阅」或「最新借阅人」的需求。
解决方案1:查询特定用户当前借阅的书籍
假设我们用Lends的自增id来判断借阅记录的新旧(如果有borrowed_at时间字段的话,用时间排序更准确,后面会说优化建议),我们可以通过子查询先找到每本书的最新借阅记录,再筛选出这些记录属于目标用户的书籍:
from django.db.models import Subquery, OuterRef # 子查询:获取每本书的最新借阅记录ID latest_lend_ids = Lends.objects.filter(book=OuterRef('pk')).order_by('-id').values('id')[:1] # 筛选出最新借阅记录属于Antony的书籍 current_borrowed_books = Book.objects.filter( lends__id=Subquery(latest_lend_ids), lends__person__username__iexact="Antony" )
解决方案2:获取所有书籍及其最新借阅用户
如果你需要拿到每本书的信息,以及它当前的最新借阅人用户名(排除历史借阅记录),可以用annotate结合子查询来实现:
from django.db.models import Subquery, OuterRef # 子查询:获取每本书最新借阅记录对应的用户名 latest_lender = Lends.objects.filter(book=OuterRef('pk')).order_by('-id').values('person__username')[:1] # 给每个Book添加最新借阅人字段 books_with_latest_lender = Book.objects.annotate( latest_borrower=Subquery(latest_lender) ).values('name', 'author', 'latest_borrower')
返回的结果里,每个条目都会包含书籍名称、作者和最新借阅人的用户名。
模型优化建议
为了让借阅记录的新旧判断更准确,建议给Lends模型添加一个自动记录借阅时间的字段:
class Lends(models.Model): book = models.ForeignKey("Book", on_delete=models.CASCADE, related_name="lends") person = models.ForeignKey("Person", on_delete=models.CASCADE, related_name="lends") borrowed_at = models.DateTimeField(auto_now_add=True) # 自动记录借阅时间
之后排序的时候就用order_by('-borrowed_at')代替order_by('-id'),这样即使手动调整过记录ID,也能准确找到最新的借阅记录。
内容的提问来源于stack exchange,提问作者RedHat
相关产品推荐
相关产品推荐

