Django中ListView与DetailView的URL解析及Key Error问题求助
解决Django中Reverse for 'detail'错误及相关视图问题
让我们一步步拆解你的问题并逐个解决:
1. 直接触发Reverse错误的根源:模板URL参数缺失
你的错误提示Reverse for 'detail' with arguments '(2,)' not found,核心原因是detail路由需要两个参数(sport_slug和pk),但模板里有一个链接只传了单个参数:
<h5 class="card-title"><a href="{% url 'streams:detail' video.id %}">{{video.name}}</a></h5>
把这个链接改成和下方"Watch Now"按钮一致的写法,传递完整的两个参数:
<h5 class="card-title"><a href="{% url 'streams:detail' video.sport.sport_slug video.pk %}">{{video.name}}</a></h5>
这样所有指向详情页的链接都能正确匹配路由规则。
2. 修复StreamSport视图的KeyError问题
StreamSport是ListView,对应的URL是<slug:sport_slug>/,这个路由里没有pk参数,所以self.kwargs['pk']会直接抛出KeyError。而且这个视图的作用是展示该运动分类下的所有视频,根本不需要过滤pk,修改后的代码如下:
class StreamSport(ListView): template_name = "stream/stream-index.html" context_object_name = 'stream_list' def get_queryset(self): self.sport = get_object_or_404(Sport, sport_slug=self.kwargs['sport_slug']) # 返回该运动分类下的所有视频,移除不必要的pk过滤逻辑 return Video.objects.filter(sport=self.sport)
3. 优化StreamDetail视图的逻辑
StreamDetail作为DetailView,默认会根据pk获取对象,你当前的get_queryset写法冗余且存在逻辑错误(self.pk = Video.objects.filter(...)得到的是QuerySet而非单个pk值)。推荐重写get_object方法,既保证逻辑清晰,又能防止用户通过修改URL访问不属于当前分类的视频:
class StreamDetail(DetailView): model = Video template_name = 'stream/detail.html' def get_object(self, queryset=None): # 先确认sport_slug对应的分类存在 sport = get_object_or_404(Sport, sport_slug=self.kwargs['sport_slug']) # 获取该分类下对应pk的视频,不存在则返回404 obj = get_object_or_404(Video, pk=self.kwargs['pk'], sport=sport) return obj
如果你更习惯用get_queryset,也可以改成这种写法(让DetailView自动从过滤后的集合中匹配pk对应的对象):
class StreamDetail(DetailView): model = Video template_name = 'stream/detail.html' def get_queryset(self): sport = get_object_or_404(Sport, sport_slug=self.kwargs['sport_slug']) # 只返回该分类下的视频,DetailView会自动匹配pk return Video.objects.filter(sport=sport)
最终验证
完成以上修改后:
- 访问
<sport_slug>/路径时,会正常展示该分类下的所有视频,KeyError问题彻底解决 - 点击视频标题或"Watch Now"按钮,会正确跳转到对应详情页,Reverse错误消失
- 详情页会严格校验视频所属分类,避免了越权访问的风险
内容的提问来源于stack exchange,提问作者Jordan Lashmar
相关产品推荐
相关产品推荐

