如何构建提取多个参数的Django REST路由?
我为我的应用程序建立了一些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 个回答
现在,"@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"
在不使用正则表达式的情况下,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和其他参数。进行修改并使用它们。
你可以使用下面的模式:
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" 请求,并且在路由中定义的参数会在类的方法中接收到。
希望这对你有帮助,如果你需要更多细节,我随时可以提供帮助。
写一个自定义的详细路由,并修改签名,以便传入你想要使用的额外参数。然后,定制一下网址路径。
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
这个网址。