在使用 Django/Django Rest Framework 时,我注意到基于类的视图中访问 URL 参数的方式不一致。
在基于通用类的视图中,我可以通过两种不同的方式访问 URL 参数 - 取决于方法:
get
方法中,我可以访问 URL 参数作为直接传递给方法的位置参数:#urls.py
path('test/<str:param1>/<int:param2>/', MyView.as_view())
#views.py
class MyView(View):
def get(self, request, param1, param2):
return JsonResponse({'param1': param1, 'param2': param2})
self.kwargs
属性
例如,当我想在 get_queryset
方法中访问相同的参数时,我必须使用 self.kwargs
#views.py
class MyView(ListView):
model = MyModel
def get_queryset(self):
param1 = self.kwargs.get('param1')
param2 = self.kwargs.get('param2')
return MyModel.objects.filter(field1=param1, field2=param2)
kwargs
任何地方访问 url 参数,但这让我产生了一些问题self.url_params
)中不是更直观吗 - 是否有任何具体原因为什么 self.kwargs
命名是首选 - 我得到了约定,但对我来说有点困惑,我们有很多其他属性,例如 idk self.data
或 self.method
,但我们没有 url 属性。self.kwargs
机制。当我试图找出原因时,我有点头疼。该机制对于使用基于类的视图似乎至关重要,但我找不到明确的解释。相反,文档仅提供示例,似乎希望开发人员“推断”URL 参数存储在 self.kwargs 中。任何人都可以解释为什么会出现这种情况吗?我很感激有关此设计决策的任何见解或解释。
通过位置参数
参数不是按位置传递,而是作为命名参数传递。事实上,如果你改变你的观点:
class MyView(View):
def get(self, request, param2, param1): # 🖘 different order
return JsonResponse({'param1': param1, 'param2': param2})
它仍然会以完全相同的方式工作。
为什么 Django/DRF 没有引入 URL 参数的专用属性?
我的猜测是你本身并不想要这样。您可以传递任意额外的 kwargs,常见的模式是:
urlpatterns = [
path('test/<str:param1>/<int:param2>/', MyView.as_view()),
path('test/<str:param1>/', MyView.as_view(), kwargs={'param2': 0}),
]
因此部分
kwargs
源自 URL 路径模式,其他部分是硬编码的,例如使路径片段可选。
本质上,
.kwargs
是视图“触发”的一组参数,这些参数本身并非来自 URL。
如果您只想要 URL 中的内容,您可以使用:
self.request.resolver_match.captured_kwargs # the ones explicitly mentioned in URL
为什么 Django 的文档中没有明确解释 self.kwargs 机制。
在内置基于类的通用视图部分中隐约提到了[Django-doc]:
实现这项工作的关键部分是,当调用基于类的视图时,各种有用的东西都存储在 self 上;以及请求 (
),这包括根据 URLconf 捕获的位置 (self.request
) 和基于名称 (self.args
) 参数。self.kwargs
但我同意这可能还不够。主要问题是设置
self.args
、self.kwargs
和 self.request
不是一成不变的:它发生在 .setup(…)
方法[Django-doc] 中,尽管重写它是非常不明智,你可以改变这种行为。我已经打开了ticket[Django-ticket]来重写文档,并使其更清楚发生了什么。