如何构建提取多个参数的Django REST路由?

11 投票
4 回答
5231 浏览
提问于 2025-04-17 20:34

我为我的应用程序建立了一些Django-Rest-Framework的API。这些API可以做一些事情,比如返回模型实例的列表,或者返回符合特定条件的模型数量。

这是我的ViewSet的样子:

class MyObjectsViewSet(viewsets.ViewSet):

    def retrieve(self,request,pk=None):
        queryset = ## Do something here to return a list of myObjects
        serializer = MyObjectsSerializer(queryset) ## MyObjectsSerializer not shown here.
        return Response(serializer.data,status=status.HTTP_200_OK)

这是我在urls.py中为这个接口设置的内容:

router = routers.DefaultRouter()
router.register(r'myObjects', views.myObjectsViewSet, base_name="myObjects")

urlpatterns = patterns('',
    ...
    url(r'^api/', include(router.urls)),
    ...
)

上面的代码让我可以给API传一个参数,并把它当作pk参数传给MyObjectsViewSet.retrieve()。所以当我在浏览器中输入/api/MyObjects/60/时,retrieve()会被调用,pk的值就是60。太好了,一切都很顺利。

但是现在我需要一个能做更多事情的API。我需要一个API,它可以接收两个数字参数(“pk”和“otherArg”),并用这两个参数调用另一个视图集(MyObjectsNewView)。这样,当我在浏览器中输入/api/MyObjects/60/59/时,MyObjectsNewView.retrieve()会被调用,参数pk的值是60,otherArg的值是59。

我该如何设计urls.py中的路由和我的Viewsets,以实现这个功能呢?

在其他情况下,当我设计非REST的URL时,我使用了正则表达式,并用像这样的表示法来从URL字符串中提取参数:(?P<MyObjectID>\d+)

看起来我应该能在这里做同样的事情。然而,它会自动接收pk参数,而我并没有在路由中指定它,所以现在我有点困惑,如何在这个路由中添加另一个参数,因为第一个pk参数似乎是神奇地出现的,没有任何正则表达式模式。

4 个回答

0

现在,"@detail_route" 在 DRF 3.8 之后被 "action" 替代了。可以这样写:

@action(methods=["get"], detail=True )
def article_sort(self, request, pk):  
    otherArg = request.query_params.get('otherArg')
    ...

当 detail 为真时,函数会从网址路径中获取 pk;所以现在完整的路径是 "/pk/article_sort/?otherArg=60"

1

在不使用正则表达式的情况下,drf(Django REST Framework)提供了一种通过类型前缀来处理路径的方法,如果你对“pk”和“otherArg”没有严格的验证要求的话。那么,

第一步:在url模式中,

path('/api/<int:id>/<otherArg>/', YourViewset.action_name, name="action_name")

第二步:在视图集(Viewset)中

@action(methods=['get'],detail=True/False)

第三步:在@action下面

def action_name(self, id, otherArg):

现在在函数中使用id和其他参数。进行修改并使用它们。

3

你可以使用下面的模式:

url(r'^resource/(?P<clientId>[A-Za-z0-9]*)/(?P<token>[A-Za-z0-9]*)$', RestResource.as_view()),

而 RestResource 类可以像这样:

class RestResource(View):
  def put(self, request, clientId, token):
    # Your code here
    return HttpResponse(json.dumps(JSON_DATA_VARIABLE), content_type = "application/json", status = 200)

  def delete(self, request, clientId, token):
    # Your code here
    return HttpResponse(json.dumps(JSON_DATA_VARIABLE), content_type = "application/json", status = 200)

这个类会接受 "PUT" 和 "DELETE" 请求,并且在路由中定义的参数会在类的方法中接收到。

希望这对你有帮助,如果你需要更多细节,我随时可以提供帮助。

6

写一个自定义的详细路由,并修改签名,以便传入你想要使用的额外参数。然后,定制一下网址路径。

from rest_framework.decorators import detail_route
from rest_framework import viewsets

class MyObjectsViewSet(viewsets.ViewSet):

    @detail_route(methods=['get'], url_path='(?P<oid>\d+)')
    def get_with_objectid(self,request,pk=None, oid=None):
        queryset = ## Do something here with oid to return a list of myObjects
        serializer = MyObjectsSerializer(queryset) ## MyObjectsSerializer not shown here.
        return Response(serializer.data,status=status.HTTP_200_OK)

现在你的视图集可以处理 /api/MyObjects/60/59/ 这个网址,其中 pk=60 和 oid=59。如果网址路径改成 url_path='/thisthing/(?P(<oid>\d+)',那么视图集就会注册 /api/MyObjects/60/thisthing/59 这个网址。

撰写回答