Django ORM外键集合查询:筛选指定日期全可用的房间
Django ORM 查询符合条件的 Room
首先修正模型代码中的拼写错误(否则无法正常运行):
class Room(models.Model): name = models.CharField(max_length=64) # 修正 Charfield -> CharField,max_lentgh -> max_length class Availability(models.Model): date = models.DateField() closed = models.BooleanField(default=False) room = models.ForeignKey(Room, on_delete=models.CASCADE) # Django 3.0+ 建议必填 on_delete 参数
针对你的需求,可通过以下步骤实现查询:
假设你要查询的日期范围是 start_date 到 end_date(比如连续7天),先计算该范围的总天数:
from datetime import date from django.db.models import Count, Q start_date = date(2024, 5, 1) end_date = date(2024, 5, 7) days_count = (end_date - start_date).days + 1 # 计算日期范围总天数,包含首尾两天
方式一:结合 annotate 和 filter 实现
available_rooms = Room.objects.annotate( # 统计当前 Room 在指定日期范围内的 Availability 记录数 valid_availability_count=Count( 'availability', filter=Q(availability__date__range=(start_date, end_date)) ) ).filter( # 条件1:记录数等于日期范围总天数,确保每天都有对应的 Availability 记录 valid_availability_count=days_count, # 条件2:日期范围内所有 Availability 的 closed 均不为 True availability__date__range=(start_date, end_date), availability__closed=False ).distinct() # 去重,避免因关联多条 Availability 导致 Room 重复
方式二:用 exclude 排除不符合条件的 Room
逻辑更直观:先筛选出日期范围记录完整的 Room,再排除其中存在 closed=True 的 Room
available_rooms = Room.objects.annotate( valid_availability_count=Count( 'availability', filter=Q(availability__date__range=(start_date, end_date)) ) ).filter( valid_availability_count=days_count ).exclude( # 排除日期范围内存在 closed=True 的 Room availability__date__range=(start_date, end_date), availability__closed=True )
逻辑说明
- 检查日期范围记录完整性:通过
annotate+Count统计每个 Room 在指定日期内的 Availability 数量,当数量等于日期范围总天数时,说明该 Room 在这段时间的每天都有对应的记录。 - 确保所有 closed 不为 True:要么通过
filter直接限定关联的 Availability 满足closed=False,要么通过exclude排除存在closed=True的 Room,两种方式都能实现需求。
内容的提问来源于stack exchange,提问作者Kihaf
相关产品推荐
相关产品推荐

