如何将含两个URL参数的Django函数视图转为DetailView?
如何在多URL参数场景下优雅使用Django的Class Based Views
当然可以!这种带两个URL参数的场景下,用Class Based Views(CBV)完全能实现优雅的写法,给你分享两种常用的解决方案:
方案一:重写get_object方法(最贴合原有函数视图逻辑)
直接继承DetailView,重写get_object方法来手动获取符合双参数条件的对象,和你原来函数视图的逻辑一一对应:
views.py
from django.views.generic.detail import DetailView from .models import Step class StepDetailView(DetailView): model = Step template_name = "courses/step_detail.html" context_object_name = "step" # 指定模板中使用的上下文变量名,和你原来的保持一致 def get_object(self, queryset=None): # 从URL参数中获取course_pk和step_pk course_pk = self.kwargs["course_pk"] step_pk = self.kwargs["step_pk"] # 用双参数查询,找不到返回404,和get_object_or_404逻辑一致 return self.get_queryset().get(course=course_pk, pk=step_pk)
urls.py
只需要把原来的函数视图替换成CBV的as_view()形式即可:
urlpatterns = [ # ... 其他URL配置 path("courses/<int:course_pk>/<int:step_pk>/", views.StepDetailView.as_view(), name='step'), ]
方案二:通过get_queryset缩小查询范围(更贴合CBV设计思路)
先通过get_queryset把查询范围限定在指定课程下的步骤,再让DetailView自动根据step_pk获取对象:
views.py
from django.views.generic.detail import DetailView from .models import Step class StepDetailView(DetailView): model = Step template_name = "courses/step_detail.html" context_object_name = "step" pk_url_kwarg = "step_pk" # 指定URL中对应Step主键的参数名 def get_queryset(self): # 先过滤出当前course下的所有Step对象 return super().get_queryset().filter(course__pk=self.kwargs["course_pk"])
这种写法的好处是:DetailView会自动在你缩小后的查询集里查找对应step_pk的对象,如果找不到同样返回404,逻辑更贴合CBV的“先限定范围再获取对象”的设计思路。
两种方案都能完美替代你原来的函数视图,选哪种全看你个人的代码习惯~
内容的提问来源于stack exchange,提问作者Jeremy Chen
相关产品推荐
相关产品推荐

