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

在Django REST Framework中通过URL多参数获取对象的实现问题

问题:如何在URL中使用多个参数获取对象

我想通过URL中的多个参数(比如customer/3/order/1/或customer/<int:customer_pk>/order/<int:pk>/)获取对象,Shell中可以正常实现:

>>> from temp.models import Customer, Order
>>> from temp.serializers import CustomerSerializer, OrderSerializer
>>> q = Order.objects.filter(customer=1).get(order_number=2)
>>> q.order_name
'fruit'

但在Django REST Framework视图中无法实现,当前代码如下:

views.py

from rest_framework import generics
from rest_framework.views import APIView

from .models import *
from .serializers import *

class OrderDetailView(generics.RetrieveDestroyAPIView):
    serializer_class = OrderSerializer 

    def get_queryset(self):
        queryset = Order.objects.filter(customer_id=self.kwargs["customer_pk"]).get(order_number=self.kwargs["pk"])
        return queryset

urls.py

from django.urls import path

from .views import *

urlpatterns = [   
    path('<int:customer_pk>/orders/<int:pk>/', OrderDetailView.as_view()),    
]

解决方案

你的代码核心问题是:RetrieveDestroyAPIView要求get_queryset方法返回QuerySet类型对象,但你用.get()直接返回了单个Order实例,这会导致视图逻辑出错(视图后续会对查询集进行迭代或过滤操作,单个实例不支持这些方法)。

下面是两种可行的修正方式:

方式1:重写get_object方法(推荐)

直接在get_object中通过两个参数获取单个对象,这是多参数筛选单个实例的标准做法:

from rest_framework import generics
from .models import Order
from .serializers import OrderSerializer

class OrderDetailView(generics.RetrieveDestroyAPIView):
    serializer_class = OrderSerializer 

    def get_object(self):
        # 根据customer_pk和order_number(对应URL中的pk参数)获取对象
        return Order.objects.get(
            customer_id=self.kwargs["customer_pk"],
            order_number=self.kwargs["pk"]
        )

方式2:修正get_queryset返回QuerySet

如果希望保留get_queryset的逻辑,需要返回过滤后的QuerySet,由视图自行根据pk(即order_number)获取对象。注意:如果Order模型的主键不是order_number,需要额外指定lookup_field:

from rest_framework import generics
from .models import Order
from .serializers import OrderSerializer

class OrderDetailView(generics.RetrieveDestroyAPIView):
    serializer_class = OrderSerializer
    # 指定用order_number作为查找字段,对应URL中的pk参数
    lookup_field = "order_number"

    def get_queryset(self):
        # 返回指定customer的所有订单QuerySet
        return Order.objects.filter(customer_id=self.kwargs["customer_pk"])

可选:优化URL路径

为了让URL语义更清晰,可以给路径加上customer/前缀:

from django.urls import path
from .views import OrderDetailView

urlpatterns = [   
    path('customer/<int:customer_pk>/orders/<int:pk>/', OrderDetailView.as_view()),    
]

内容的提问来源于stack exchange,提问作者mRezaAnanta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 15:05:31