You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 02:37:30