何时将HTTP方法映射到视图方法Django Rest Framework

7

我曾经看到过这样实现viewsets的方法:

在Django Rest Framework文档中,我们可以对以下代码进行扩展:

"如果需要的话,我们可以将该viewset绑定到两个单独的视图中,如下所示:"

user_list = UserViewSet.as_view({'get': 'list'})
user_detail = UserViewSet.as_view({'get': 'retrieve'})

user_listuser_detail会被连接到/使用在哪里?

尤其是在使用viewsets或通用视图时,什么时候会映射http方法?

因为我看过一些不使用映射的视图集的示例,并且使用它们。我们可以谈论一下这是如何工作和连接的吗?

task_list = TaskViewSet.as_view({
    'get': 'list',
    'post': 'create'
})

task_detail = TaskViewSet.as_view({
    'get': 'retrieve',
    'put': 'update',
    'patch': 'partial_update',
    'delete': 'destroy'
})

task_router = DefaultRouter()
task_router.register(r'tasks', TaskViewSet)

并且关于这个,有什么问题吗?
@detail_route(methods=['post'])
    def set_password(self, request, pk=None):

如果我们有路由装饰器,为什么还需要URL映射?它们之间有什么区别?
1个回答

11

对于您的第一个问题,关于连接UserViewSet,您可以在urls文件中如下使用:

urlpatterns = [
    url(
        r'^users/$',
        UserViewSet.as_view({'get': 'list'}),
        name='user-list',
    ),
    url(
        r'^users/(?P<pk>\d+)/$',
        UserViewSet.as_view({'get': 'retrieve'}),
        name='user-detail',
    ),
]

这是您的用户模型的只读实现,使用ViewSets。如果您想列出所有用户,可以请求/users/,如果您想获取id为1的用户,则应请求/users/1/

您应该明白这里有两种操作:对您的模型进行操作,例如列出用户或创建新用户;以及对模型实例进行操作。例如,如果您想检索、更新或删除用户实例,您需要在URL中包含用户的主键,以便获取该用户。

您的TaskViewSet不是只读的,因此让我们看看该类应该是什么样子。

class TaskViewSet(ModelViewSet):
    queryset = Task
    serializer_class = TaskSerializer
    lookup_field = 'pk'  # This is the default
    lookup_url_kwarg = 'pk'  # This is the default

以下是您可以在urls文件中实现的简单通用的ModelViewSet:

urlpatterns = [
    url(
        r'^tasks/$',
        TaskViewSet.as_view({'get': 'list', 'post': 'create'}),
        name='task-list',
    ),
    url(
        r'^tasks/(?P<pk>\d+)/$',
        TaskViewSet.as_view({'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'}),
        name='task-detail',
    ),
]
现在您可以对您的模型进行任何操作,包括列出、创建、检索、更新和删除对象。使用ModelViewSet,您会发现有一种模式正在形成,这就是路由器的便利之处。Django Rest Framework的路由器实现基本上通过获取路径和ViewSet,然后构造URL来工作。
在此示例中,我们使用SimpleRouter生成我们的URL模式。
router = SimpleRouter()
router.register('users', UserViewSet)  # UserViewSet is ReadOnlyModelViewSet
router.register('tasks', TaskViewSet)  # TaskViewSet is ModelViewSet
urlpatterns = [] + router.urls

这将生成:

urlpatterns = [
    url(
        r'^users/$',
        UserViewSet.as_view({'get': 'list'}),
        name='user-list',
    ),
    url(
        r'^users/(?P<pk>\d+)/$',
        UserViewSet.as_view({'get': 'retrieve'}),
        name='user-detail',
    ),
    url(
        r'^tasks/$',
        TaskViewSet.as_view({'get': 'list', 'post': 'create'}),
        name='task-list',
    ),
    url(
        r'^tasks/(?P<pk>\d+)/$',
        TaskViewSet.as_view({'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'}),
        name='task-detail',
    ),
]

到目前为止,我希望这些内容都能让你理解,你可以看到如何使用这些类来减少需要编写的代码。

现在我将解释 @detail_route@list_route 装饰器的作用。这些装饰器帮助 Router 类在您的 ViewSet 上注册自定义方法。

对于 rest framework 3.8 以上版本,@detail_route@list_route 已经被弃用,取而代之的是 @action 装饰器。使用 @action(detail=True, ...) 代替 @detail_route(...) ,使用 @action(detail=False, ...) 代替 @list_route(...)

如果您想要提供一些以 CSV 格式下载模型报告数据为例,应使用 @list_route 装饰器来调用 Model 上有意义的操作,而不是该模型的实例。 如果您想要针对 Model 的实例执行操作,则应使用 @detail_route 装饰器。 我将扩展之前的 TaskViewSet 示例。

class TaskViewSet(ModelViewSet):
    queryset = Task
    serializer_class = TaskSerializer
    lookup_field = 'pk'  # This is the default
    lookup_url_kwarg = 'pk'  # This is the default

    @list_route(methods=['get'])
    def download(self, request, *args, **kwargs):
        """Download queryset as xlsx"""
        qs = self.get_queryset()
        return queryset_to_excel(qs)  # simple example

    @detail_route(methods=['get'])
    def details(self, request, *args, **kwargs):
        """Return intricate details of Task"""
        object = self.get_object()
        return object.get_intricate_task_details()

如果我们使用此 TaskViewSet 与路由器:

router = SimpleRouter()
router.register('tasks', TaskViewSet)
urlpatterns = [] + router.urls

我已经在列表上添加了一个下载方法,可以将查询集以Excel文件的形式下载,并且我还添加了一个详细信息方法到详情视图中,它会返回一些可能很耗费资源的额外信息,因此我们不希望它出现在普通的详细响应中。然后我们将得到一个如下的URL配置:

urlpatterns = [
    url(
        r'^tasks/$',
        TaskViewSet.as_view({'get': 'list', 'post': 'create'}),
        name='task-list',
    ),
    url(
        r'^tasks/download/$',
        TaskViewSet.as_view({'get': 'download'}),
        name='task-download',
    ),
    url(
        r'^tasks/(?P<pk>\d+)/$',
        TaskViewSet.as_view({'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'}),
        name='task-detail',
    ),
    url(
        r'^tasks/(?P<pk>\d+)/details/$',
        TaskViewSet.as_view({'get': 'detail'}),
        name='task-details',
    ),
]

路由器现在已经为TaskViewSet上定义的自定义方法生成了额外的路由。

我建议阅读有关ViewSet和SimpleRouter的rest框架文档。

http://www.django-rest-framework.org/api-guide/viewsets/#modelviewset
http://www.django-rest-framework.org/api-guide/routers/#simplerouter


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接