Django如何用select_related预取每个Table关联的最新Reservation记录
Django餐厅桌台关联最新有效预约查询实现方案
前置调整:补充Reservation模型必要字段
要判断预约有效性、区分预约的时间先后,需要先给Reservation模型补充字段,调整后代码如下:
from django.db import models class Table(models.Model): def __str__(self): return str(self.pk) class Reservation(models.Model): table = models.ForeignKey( Table, on_delete=models.CASCADE, blank=False, null=False, related_name='reservations' ) # 预约时间,用于排序取最新 reserve_time = models.DateTimeField(verbose_name="预约时间") # 有效标记,可根据业务规则替换(比如用状态选择项、或直接用时间判定是否过期) is_valid = models.BooleanField(default=True, verbose_name="是否有效") def __str__(self): return str(self.pk)
实现方案1:预取所有有效预约(适合需要多条有效预约的场景)
用Django的Prefetch对象自定义预取规则,一次性查询所有桌台的关联有效预约,避免N+1查询问题:
from django.db.models import Prefetch # 构造有效预约查询集,按时间倒序排列,最新的排在首位 valid_reservation_queryset = Reservation.objects.filter(is_valid=True).order_by('-reserve_time') # 预取关联数据,存入自定义属性latest_valid_reservations table_list = Table.objects.prefetch_related( Prefetch( 'reservations', queryset=valid_reservation_queryset, to_attr='latest_valid_reservations' ) ).all() # 遍历使用示例 for table in table_list: # 取最新的第一条,无有效预约则为None latest_res = table.latest_valid_reservations[0] if table.latest_valid_reservations else None # 你的业务逻辑
实现方案2:子查询注解最新预约(仅需最新一条时性能更优)
如果只需要每个桌台的最新一条有效预约,用子查询注解的方式减少数据查询量:
from django.db.models import OuterRef, Subquery # 子查询:匹配对应桌台的最新有效预约ID latest_res_sub = Reservation.objects.filter( table=OuterRef('pk'), is_valid=True ).order_by('-reserve_time').values('pk')[:1] # 给桌台查询集注解最新预约ID,同时关联查询预约数据 table_list = Table.objects.annotate( latest_reservation_id=Subquery(latest_res_sub) ).select_related('latest_reservation').all() # 遍历使用示例 for table in table_list: latest_res = table.latest_reservation # 你的业务逻辑
说明:如果你的业务对有效预约的判定规则不同(比如预约时间大于当前时间才算有效),只需要调整
filter内的筛选条件即可。
内容的提问来源于stack exchange,提问作者Poula Adel
相关产品推荐
相关产品推荐

