26

本质上,我试图找到一种在不创建自定义路由器的情况下将更多视图附加到路由器的好方法。有什么好方法可以做到这一点?

这有点等同于我想要完成的事情。为了这个问题,变量名称已更改,我要介绍的示例方法非常简化。

路由器:

router = routers.SimpleRouter(trailing_slash=False)
router.register(r'myobjects', MyObjectViewSet, base_name='myobjects')
urlpatterns = router.urls

视图集

class MyObjectsViewSet(viewsets.ViewSet):
""" Provides API Methods to manage MyObjects. """

def list(self, request):
    """ Returns a list of MyObjects. """
    data = get_list_of_myobjects()
    return Response(data)

def retrieve(self, request, pk):
    """ Returns a single MyObject. """
    data = fetch_my_object(pk)
    return Response(data)

def destroy(self, request, pk):
    """ Deletes a single MyObject. """
    fetch_my_object_and_delete(pk)
            return Response()

我需要包括的另一种方法类型的一个示例。(其中有很多):

def get_locations(self, request):
    """ Returns a list of location objects somehow related to MyObject """
    locations = calculate_something()
    return Response(locations)

最终结果是以下 URL 可以正常工作并“干净”地实施。

GET example.com/myobjects/123/locations
4

4 回答 4

24

只要您只是想提出请求,上面mariodev 给出的答案是正确的。GET

如果你想要POST一个附加到 ViewSet 的函数,你需要使用action装饰器:

from rest_framework.decorators import action, link
from rest_framework.response import Response

class MyObjectsViewSet(viewsets.ViewSet):

    # For GET Requests
    @link()
    def get_locations(self, request):
        """ Returns a list of location objects somehow related to MyObject """
        locations = calculate_something()
        return Response(locations)

    # For POST Requests
    @action()
    def update_location(self, request, pk):
        """ Updates the object identified by the pk """
        location = self.get_object()
        location.field = update_location_field() # your custom code
        location.save()

        # ...create a serializer and return with updated data...

然后你会POST得到一个格式如下的 URL: /myobjects/123/update_location/

如果您有兴趣,http://www.django-rest-framework.org/api-guide/viewsets/#marking-extra-actions-for-routing有更多信息!

于 2014-01-20T17:24:59.980 回答
15

您现在可以使用 list_route 和 detail_route 装饰器执行此操作:http: //www.django-rest-framework.org/api-guide/viewsets/#marking-extra-actions-for-routing

例如:

from rest_framework.decorators import list_route
from rest_framework.response import Response
...

class MyObjectsViewSet(viewsets.ViewSet):
    ...

    @list_route()
    def locations(self, request):
        queryset = get_locations()
        serializer = LocationSerializer(queryset, many=True)
        return Response(serializer.data)
于 2015-06-30T08:56:51.720 回答
8

您像现在一样定义方法,但是您需要使用与方法名称相同的 url 并添加链接装饰器,因此对于

/myobjects/123/locations/

你添加这样的方法

@link(permission_classes=[...])
def locations(self, request, pk=None):
    ...

路由器会自动选择它。

于 2013-09-23T23:40:24.733 回答
3

路由到 ViewSet 上的额外方法

我认为您可能需要手动路由该方法,即 The Old-Fashioned Way™。

首先将该方法作为单独的视图拉出:

   set_password_view = UserViewSet.as_view({'post': 'set_password'})

(或类似的)

然后分配您的网址:

   url(r'^users/username_available/$', set_password_view, name-=...)

(或者这样的)

关于 SO有一个相关的问题。

于 2014-01-14T08:37:44.397 回答