为啥我无法在 Django 路由器中注册“.as_view()”(使用 djangorestframework-simplejwt)?

Posted

技术标签:

【中文标题】为啥我无法在 Django 路由器中注册“.as_view()”(使用 djangorestframework-simplejwt)?【英文标题】:Why I cannot register '.as_view()' in the Django router (using djangorestframework-simplejwt)?为什么我无法在 Django 路由器中注册“.as_view()”(使用 djangorestframework-simplejwt)? 【发布时间】:2021-03-27 14:52:36 【问题描述】:

我一直在尝试将 djangorestframework-simplejwt 添加到我的 web 应用程序中,并且每当我使用路由器添加视图时(请参阅下面代码中的 2 个注释路由器) - 我收到一个错误(请参阅回溯)。

当添加网址as the documentation says - 在urlpatterns 变量下 - 它可以正常工作而不会出现任何错误。我想知道为什么这不能通过router.register(..) 工作,并且为了良好的秩序(和我的强迫症),是否可以将其从 urlpatterns 变量移到路由器。

from django.urls import path, include
from rest_framework import routers
from . import views

from django.conf.urls import url
from django.contrib import admin
from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
)

app_name = 'myapi'

router = routers.DefaultRouter()
router.register(r'posts', views.PostViewSet)
router.register(r'user', views.UserViewSet)
router.register(r'likes', views.LikesViewSet)
# router.register(r'token',TokenObtainPairView.as_view())
# router.register(r'token/refresh',jwt_views.TokenRefreshView.as_view())

urlpatterns = [
    path('', include(router.urls)), 
    path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]

追溯:

Exception in thread django-main-thread:
Traceback (most recent call last):
  File "/home/test/anaconda3/envs/ppproject/lib/python3.9/threading.py", line 954, in _bootstrap_inner
    self.run()
  File "/home/test/anaconda3/envs/ppproject/lib/python3.9/threading.py", line 892, in run
    self._target(*self._args, **self._kwargs)
  File "/home/test/anaconda3/envs/ppproject/lib/python3.9/site-packages/django/utils/autoreload.py", line 53, in wrapper
    fn(*args, **kwargs)
  File "/home/test/anaconda3/envs/ppproject/lib/python3.9/site-packages/django/core/management/commands/runserver.py", line 118, in inner_run
    self.check(display_num_errors=True)
  File "/home/test/anaconda3/envs/ppproject/lib/python3.9/site-packages/django/core/management/base.py", line 392, in check
    all_issues = checks.run_checks(
  File "/home/test/anaconda3/envs/ppproject/lib/python3.9/site-packages/django/core/checks/registry.py", line 70, in run_checks
    new_errors = check(app_configs=app_configs, databases=databases)
  File "/home/test/anaconda3/envs/ppproject/lib/python3.9/site-packages/django/core/checks/urls.py", line 13, in check_url_config
    return check_resolver(resolver)
  File "/home/test/anaconda3/envs/ppproject/lib/python3.9/site-packages/django/core/checks/urls.py", line 23, in check_resolver
    return check_method()
  File "/home/test/anaconda3/envs/ppproject/lib/python3.9/site-packages/django/urls/resolvers.py", line 408, in check
    for pattern in self.url_patterns:
  File "/home/test/anaconda3/envs/ppproject/lib/python3.9/site-packages/django/utils/functional.py", line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/home/test/anaconda3/envs/ppproject/lib/python3.9/site-packages/django/urls/resolvers.py", line 589, in url_patterns
    patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
  File "/home/test/anaconda3/envs/ppproject/lib/python3.9/site-packages/django/utils/functional.py", line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/home/test/anaconda3/envs/ppproject/lib/python3.9/site-packages/django/urls/resolvers.py", line 582, in urlconf_module
    return import_module(self.urlconf_name)
  File "/home/test/anaconda3/envs/ppproject/lib/python3.9/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 790, in exec_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "/home/test/Projects/ppproject/src/ufb/urls.py", line 25, in <module>
    path('api/', include('myapi.urls', namespace='myapi')),
  File "/home/test/anaconda3/envs/ppproject/lib/python3.9/site-packages/django/urls/conf.py", line 34, in include
    urlconf_module = import_module(urlconf_module)
  File "/home/test/anaconda3/envs/ppproject/lib/python3.9/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 790, in exec_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "/home/test/Projects/ppproject/src/myapi/urls.py", line 18, in <module>
    router.register(r'token',TokenObtainPairView.as_view())
  File "/home/test/anaconda3/envs/ppproject/lib/python3.9/site-packages/rest_framework/routers.py", line 54, in register
    basename = self.get_default_basename(viewset)
  File "/home/test/anaconda3/envs/ppproject/lib/python3.9/site-packages/rest_framework/routers.py", line 137, in get_default_basename
    assert queryset is not None, '`basename` argument not specified, and could ' \
AssertionError: `basename` argument not specified, and could not automatically determine the name from the viewset, as it does not have a `.queryset` attribute.

【问题讨论】:

将视图传递给路由器是没有意义的,因为路由器的想法是构造多个路径:一个用于详细信息,一个用于列表等. 这些都是组合在一个视图集中的不同视图。路由器为单个视图构建路径。 FWIW,这个问题唯一合理的标签是django-rest-framework 【参考方案1】:

路由器使用 ViewSets 而不是 API 视图,因此您无法在该级别添加它们。

在 Django 领域,每个 url 都映射到一个视图 function,而 Router 的工作就是将该 ViewSet 转换为 django 的 path 知道如何处理的函数列表,通过将GET 路由到list() 函数等。所以router.urls 是django path 实例的列表。

如果你真的想迷惑别人,你可以even do it manually!

snippet_list = SnippetViewSet.as_view(
    'get': 'list',
    'post': 'create'
)

path('snippets/', snippet_list, name='snippet-list'),

您现在添加它们的方式是正确的。 as_view 是一个 DRF 函数,它将APIView 或相关类转换为 django 的path 使用的视图函数。

我有一个route() helper,您可能会觉得它有帮助。它统一了视图、'.urls'、视图集的路由,并替换了path()。我发现这是我多年来最大的挫败感之一。

urlpatterns = [
    route('students/', 'student.urls'),
    route('users/', UserViewSet, name='user'),
    route('register/', RegisterView, name='register'),
    ...

【讨论】:

以上是关于为啥我无法在 Django 路由器中注册“.as_view()”(使用 djangorestframework-simplejwt)?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 Django 的登录表单中显示错误?

为啥参数中带有点的路由无法匹配?

DRF视图和路由

为啥 webpack 在使用“import * as _”时不会对 lodash 进行摇树?

为啥通过 django rest 框架注册用户时出现状态码错误

为啥 MySQL DELETE 无法对子查询使用索引?