Django REST Framework中OPTIONS请求触发AssertionError错误求助
解决Django ViewSet OPTIONS请求AssertionError问题
当向api/my_object/发送OPTIONS请求时,Django REST Framework的默认元数据(metadata)处理逻辑会检查视图的lookup配置。由于ModelViewSet默认期望URL包含pk参数,但list接口的URL未提供该参数,因此触发断言错误。
以下是几种可行的解决方法:
方法一:自定义Metadata类跳过lookup参数检查
重写默认的Metadata类,针对list动作移除不必要的pk参数校验,然后在ViewSet中指定使用该类:
from rest_framework.metadata import SimpleMetadata class NoLookupMetadata(SimpleMetadata): def determine_metadata(self, request, view): if view.action == 'list': return { 'name': view.get_view_name(), 'description': view.get_view_description(), 'allowed_methods': [m.upper() for m in view.allowed_methods], 'actions': self.determine_actions(request, view) } return super().determine_metadata(request, view) class My_ViewSet(viewsets.ModelViewSet): serializer_class = My_Serializer queryset = My_Object.objects.all() metadata_class = NoLookupMetadata # 绑定自定义Metadata类 def list(self, request): return Response() def retrieve(self, request, pk=None): my_object = get_object_or_404(My_Object, id=pk) return Response(my_object.id)
方法二:在ViewSet中直接重写metadata方法
在ViewSet里重写metadata方法,针对OPTIONS请求的list动作返回自定义元数据,避免触发pk检查:
class My_ViewSet(viewsets.ModelViewSet): serializer_class = My_Serializer queryset = My_Object.objects.all() def metadata(self, request): if request.method == 'OPTIONS' and self.action == 'list': return { 'allowed_methods': [m.upper() for m in self.allowed_methods], 'name': self.get_view_name(), 'description': self.get_view_description() } return super().metadata(request) def list(self, request): return Response() def retrieve(self, request, pk=None): my_object = get_object_or_404(My_Object, id=pk) return Response(my_object.id)
方法三:拆分视图独立处理list和retrieve
将list和retrieve逻辑拆分为两个独立的通用视图,避免ModelViewSet默认配置的冲突:
# views.py from rest_framework.generics import ListAPIView, RetrieveAPIView class MyListAPIView(ListAPIView): serializer_class = My_Serializer queryset = My_Object.objects.all() def list(self, request): return Response() class MyRetrieveAPIView(RetrieveAPIView): serializer_class = My_Serializer queryset = My_Object.objects.all() lookup_field = 'id' def retrieve(self, request, pk=None): my_object = get_object_or_404(My_Object, id=pk) return Response(my_object.id) # urls.py urlpatterns = [ path('api/my_object/', MyListAPIView.as_view()), path('api/my_object/<int:pk>/', MyRetrieveAPIView.as_view()), ]
内容的提问来源于stack exchange,提问作者SWater
相关产品推荐
相关产品推荐

