在Django中如何实现每个频道仅查询3条关联视频?
解决方案
要实现每个频道取3条最高per_sec_views的视频,你可以用Django的窗口函数或者子查询+聚合的方式,以下是具体实现:
方法一:使用窗口函数(Django 2.0+ 推荐)
窗口函数可以给每个频道内的视频按播放量排序并生成行号,之后筛选行号≤3的结果即可:
from django.db.models import Window, F from django.db.models.functions import RowNumber def each_channel_three_videos(request): # 给每个频道的视频按per_sec_views降序生成行号 videos = YTVideo.objects.select_related('channel')\ .filter(channel__category__slug='vlogs')\ .annotate( row_num=Window( expression=RowNumber(), partition_by=F('channel_id'), order_by=F('per_sec_views').desc() ) )\ .filter(row_num__lte=3) # 只保留每个频道前3条 context = { 'videos': videos, } return render(request, 'videos.html', context)
说明:
partition_by=F('channel_id'):按频道ID分组order_by=F('per_sec_views').desc():每组内按per_sec_views降序排序row_num__lte=3:筛选每组的前3条数据
方法二:使用子查询(兼容低版本Django)
如果你的Django版本较低不支持窗口函数,可以用子查询+聚合的方式,先获取每个频道的前3条视频ID,再批量查询:
from django.db.models import Subquery, OuterRef def each_channel_three_videos(request): # 子查询:获取单个频道的前3条视频ID top_videos_subquery = YTVideo.objects.filter( channel_id=OuterRef('channel_id') ).order_by('-per_sec_views')[:3].values_list('id', flat=True) # 筛选所有在子查询结果里的视频 videos = YTVideo.objects.select_related('channel')\ .filter(channel__category__slug='vlogs')\ .filter(id__in=Subquery(top_videos_subquery))\ .order_by('channel_id', '-per_sec_views') # 按频道+播放量排序 context = { 'videos': videos, } return render(request, 'videos.html', context)
说明:
OuterRef('channel_id'):引用外部查询的频道ID,实现每个频道单独查询前3条id__in=Subquery(...):过滤出所有符合条件的视频- 最后
order_by可以让结果按频道分组展示,方便前端渲染
前端渲染建议
如果需要按频道分组展示视频,可以在视图里把结果整理成字典:
from collections import defaultdict def each_channel_three_videos(request): # 先按上面任意一种方法获取videos videos_by_channel = defaultdict(list) for video in videos: videos_by_channel[video.channel].append(video) context = { 'videos_by_channel': videos_by_channel, } return render(request, 'videos.html', context)
前端模板可以这样遍历:
{% for channel, videos in videos_by_channel.items %} <h3>{{ channel.channel_title }}</h3> <ul> {% for video in videos %} <li>{{ video.title }}</li> {% endfor %} </ul> {% endfor %}
内容的提问来源于stack exchange,提问作者afi
相关产品推荐
相关产品推荐

