无法从 Django ViewSet 引发 APIException
Cannot raise APIException from Django ViewSet
我在 ViewSet
中有一个方法,我想在其中验证 request.data
是一个列表。如果不是,我想提出一个 ParseError()
.
但是,当我实际提出 said ParseError
时,我的代码崩溃了,我不明白为什么。它是 APIException
的子类,documentation 声明自动处理。
# views.py
class MyViewSet(viewsets.GenericViewSet):
...
@action(methods=['post'], detail=False, url_path='bulk-create')
def bulk_create(self, request, *args, **kwargs):
# Assert that request.data is a list of objects
if not isinstance(request.data, list):
raise ParseError("Expected the data to be in list format.")
# Actually process incoming data
...
使用列表以外的任何内容调用路由会正确触发我的 if
语句,但没有使用 status.HTTP_400_BAD_REQUEST
返回正确的响应,服务器崩溃并且我收到以下错误:
Traceback (most recent call last):
2022-05-17T12:23:45.366216553Z File "/opt/venv/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
2022-05-17T12:23:45.366221178Z response = get_response(request)
2022-05-17T12:23:45.366223345Z File "/opt/venv/lib/python3.9/site-packages/debug_toolbar/middleware.py", line 67, in __call__
2022-05-17T12:23:45.366225470Z panel.generate_stats(request, response)
2022-05-17T12:23:45.366238220Z File "/opt/venv/lib/python3.9/site-packages/debug_toolbar/panels/request.py", line 30, in generate_stats
2022-05-17T12:23:45.366240470Z "post": get_sorted_request_variable(request.POST),
2022-05-17T12:23:45.366346803Z File "/opt/venv/lib/python3.9/site-packages/debug_toolbar/utils.py", line 227, in get_sorted_request_variable
2022-05-17T12:23:45.366352511Z return [(k, variable.getlist(k)) for k in sorted(variable)]
2022-05-17T12:23:45.366354803Z TypeError: '<' not supported between instances of 'dict' and 'dict'
由于错误日志,我怀疑 django-debug-toolbar
与我的问题有关。我已经尝试将它移动到我的中间件配置中的每个位置,但这并没有解决我的问题。
# settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'debug_toolbar.middleware.DebugToolbarMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django_currentuser.middleware.ThreadLocalUserMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'rollbar.contrib.django.middleware.RollbarNotifierMiddleware',
]
编辑:我知道排序有时会失败,但为什么首先会发生这种排序?
编辑 2:django-debug-toolbar
的人帮助我确认,是 JSON 格式化为数组在引发时与库发生冲突一个例外。
感谢 django-debug-toolbar
的优秀人员,库现在也可以处理 POST.data
中的 top-level 个数组。 https://github.com/jazzband/django-debug-toolbar/pull/1624
可悲的是,我 运行 直接进入了与 Django 测试系统相同的问题...
# test_with_error.py
from rest_framework.test import APITestCase
class DonationBulkCreateRouteTestCase(APITestCase):
def test_route_permissions(self):
self.client.post(
path="/bulk-create/",
data=json.dumps([], default=json_serializer)
)
# log.txt
File "/opt/venv/lib/python3.9/site-packages/django/test/client.py", line 245, in encode_multipart
for (key, value) in data.items():
AttributeError: 'str' object has no attribute 'items'
因此,虽然 top-level 数组是有效的 JSON,但我决定将我的数据包装在一个附加对象中,并在其中传递列表。这还有一个额外的好处,那就是将来更容易扩展,因为我可以在不破坏现有代码的情况下自由添加密钥。
我在 ViewSet
中有一个方法,我想在其中验证 request.data
是一个列表。如果不是,我想提出一个 ParseError()
.
但是,当我实际提出 said ParseError
时,我的代码崩溃了,我不明白为什么。它是 APIException
的子类,documentation 声明自动处理。
# views.py
class MyViewSet(viewsets.GenericViewSet):
...
@action(methods=['post'], detail=False, url_path='bulk-create')
def bulk_create(self, request, *args, **kwargs):
# Assert that request.data is a list of objects
if not isinstance(request.data, list):
raise ParseError("Expected the data to be in list format.")
# Actually process incoming data
...
使用列表以外的任何内容调用路由会正确触发我的 if
语句,但没有使用 status.HTTP_400_BAD_REQUEST
返回正确的响应,服务器崩溃并且我收到以下错误:
Traceback (most recent call last):
2022-05-17T12:23:45.366216553Z File "/opt/venv/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
2022-05-17T12:23:45.366221178Z response = get_response(request)
2022-05-17T12:23:45.366223345Z File "/opt/venv/lib/python3.9/site-packages/debug_toolbar/middleware.py", line 67, in __call__
2022-05-17T12:23:45.366225470Z panel.generate_stats(request, response)
2022-05-17T12:23:45.366238220Z File "/opt/venv/lib/python3.9/site-packages/debug_toolbar/panels/request.py", line 30, in generate_stats
2022-05-17T12:23:45.366240470Z "post": get_sorted_request_variable(request.POST),
2022-05-17T12:23:45.366346803Z File "/opt/venv/lib/python3.9/site-packages/debug_toolbar/utils.py", line 227, in get_sorted_request_variable
2022-05-17T12:23:45.366352511Z return [(k, variable.getlist(k)) for k in sorted(variable)]
2022-05-17T12:23:45.366354803Z TypeError: '<' not supported between instances of 'dict' and 'dict'
由于错误日志,我怀疑 django-debug-toolbar
与我的问题有关。我已经尝试将它移动到我的中间件配置中的每个位置,但这并没有解决我的问题。
# settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'debug_toolbar.middleware.DebugToolbarMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django_currentuser.middleware.ThreadLocalUserMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'rollbar.contrib.django.middleware.RollbarNotifierMiddleware',
]
编辑:我知道排序有时会失败,但为什么首先会发生这种排序?
编辑 2:django-debug-toolbar
的人帮助我确认,是 JSON 格式化为数组在引发时与库发生冲突一个例外。
感谢 django-debug-toolbar
的优秀人员,库现在也可以处理 POST.data
中的 top-level 个数组。 https://github.com/jazzband/django-debug-toolbar/pull/1624
可悲的是,我 运行 直接进入了与 Django 测试系统相同的问题...
# test_with_error.py
from rest_framework.test import APITestCase
class DonationBulkCreateRouteTestCase(APITestCase):
def test_route_permissions(self):
self.client.post(
path="/bulk-create/",
data=json.dumps([], default=json_serializer)
)
# log.txt
File "/opt/venv/lib/python3.9/site-packages/django/test/client.py", line 245, in encode_multipart
for (key, value) in data.items():
AttributeError: 'str' object has no attribute 'items'
因此,虽然 top-level 数组是有效的 JSON,但我决定将我的数据包装在一个附加对象中,并在其中传递列表。这还有一个额外的好处,那就是将来更容易扩展,因为我可以在不破坏现有代码的情况下自由添加密钥。