Django:如何处理QuerySet以展示用户偏好目的地交集且不改动原对象
完全可以在View层实现,给你两种实用方案:
方案一:内存中给航空公司对象添加过滤后的目的地属性
先拿到当前用户的偏好目的地ID集合,再遍历查询到的航空公司列表,给每个对象新增一个filtered_destinations属性存储交集结果:
# 视图中的代码 user_preferred_ids = user.preferredDestinations.values_list('id', flat=True) airlineSet = Airline.objects.filter(customers=user.id) # 给每个航空公司添加过滤后的目的地属性 for airline in airlineSet: airline.filtered_destinations = airline.destinations.filter(id__in=user_preferred_ids)
模板里直接遍历airline.filtered_destinations即可展示交集内容,不会改动原始的destinations属性。
方案二:用Prefetch预取优化查询性能
如果航空公司数量较多,方案一会触发N+1次数据库查询(每个航空公司单独查一次目的地),用Django的Prefetch可以一次性预取所有需要的交集数据,性能更优:
from django.db.models import Prefetch # 视图中的代码 user_preferred_dests = user.preferredDestinations.all() airlineSet = Airline.objects.filter(customers=user.id).prefetch_related( Prefetch( # 指定要预取的多对多字段名 'destinations', # 自定义查询集:只取和用户偏好重叠的目的地 queryset=City.objects.filter(id__in=user_preferred_dests), # 将预取结果存到自定义属性,避免覆盖原始destinations to_attr='filtered_destinations' ) )
模板同样使用airline.filtered_destinations展示即可,这种方式只会触发3次数据库查询,比方案一高效很多。
补充说明
Annotation不太适合这个场景,因为它主要用来给查询集添加聚合类字段(比如数量、求和值),而你需要的是一个对象集合(交集的城市列表),所以上面两种方法更直接。另外,两种方案都是给查询到的对象添加额外属性,完全不会修改数据库里的原始数据,不用担心影响其他业务逻辑。
内容的提问来源于stack exchange,提问作者Julio Martí nez
相关产品推荐
相关产品推荐

