【问题标题】:How to properly match an API to Views in Django如何正确地将 API 与 Django 中的视图匹配
【发布时间】:2018-09-20 22:39:35
【问题描述】:

我的问题归结为 Django 中 REST 和视图的最佳实践之一。我正在为我当前的项目重新设计 REST api,其中包括重新设计我们的视图(传统 MVC 中的控制器)。目前,一切都通过 POST 请求进行隧道传输,即使是应该是简单 GET 的东西。

从休息的角度来看,所有作业的列表应该返回一个如下 URL:

api/jobs/

应使用以下命令检索单个作业(ID 为 1):

api/jobs/1

最后这应该返回属于作业 1 的所有任务

api/jobs/1/tasks/

这是我在新系统中使用的理念,但我对实施感到困惑。这两者应该在 Django 中获得自己的视图,还是应该由一个视图处理两者。

目前我正在使用一个视图,所有相关的 url 都会路由到它,逻辑是这样的;

def get(self, request, id=None, task_id=None):

    if id is None:
        return Job.objects.all()  # This will be the LIST'
    if task_id is not None:
        return Job.objects.get(id=id).task_set.all()
    return Job.objects.get(id=id)

如果增加更多复杂性,这似乎会导致非常复杂和冗长的视图。如果我想为其他资源的任务逻辑添加类似的逻辑,我会继续添加到视图中,还是应该每个都有自己的视图?

【问题讨论】:

    标签: django rest model-view-controller django-rest-framework


    【解决方案1】:

    Django 存在Rest Framework,它提供了休息视图、路由器、序列化程序等。您应该主要查看Viewsets and routers | Rest Framework,这正是您所需要的。

    【讨论】:

      【解决方案2】:

      我认为您不应该将所有这些都包含在一个视图中。我会使用两个 ModelViewSet 并将它们的 url 构造如下:

      views.py

      class JobViewSet(ModelViewSet):
          serializer_class = JobSerializer
          queryset = Job.objects.all()
      
      class TaskViewSet(ModelViewSet):
          serializer_class = TaskSerializer
          queryset = Task.objects.all()
      
          def get_queryset(self, request, *args, **kwargs):
              # Override get_queryset to allow filtering by `job_id` url kwarg.
              qs = self.queryset
              if kwargs.get('job_id'):
                  job = Job.objects.get(pk=kwargs.get('job_id'))
                  qs = qs.filter(job=job)
              return qs
      

      urls.py

      urlpatterns = [
          url(
              r'^api/jobs/$', 
              JobViewSet.as_view({'get': 'list', 'post': 'create'}
          ),
          url(
              r'^api/jobs/(?P<pk>\d+)/$', 
              JobViewSet.as_view({'get': 'retrieve', 'patch': 'update', 'patch': 'partial_update', 'delete': 'destroy'}
          ),
          url(
              r'^api/jobs/(?P<job_id>\d+)/tasks/$', 
              TaskViewSet.as_view({'get': 'list', 'post': 'create'}
          ),
          url(
              r'^api/jobs/(?P<job_id>\d+)/tasks/(?P<pk>\d+)/$', 
              TaskViewSet.as_view({'get': 'retrieve', 'patch': 'update', 'patch': 'partial_update', 'delete': 'destroy'}
          ),
      ]
      

      我已经避免使用 Rest Framework 路由器,但它们本质上会为单个查询集生成与此类似的路由,嵌套查询集使用路由器变得更加复杂。您可能会注意到,您的路由需要 ViewSets 的 pk 关键字参数来获取对象的单个实例,这是 ModelViewSets 的默认查找值。一旦我们将/tasks/ 端点嵌套在/jobs/ 端点下方,我们必须将作业pk 关键字参数更改为jobs_id,这样视图就不会将其用作任务的默认查找值。 jobs_id 用于自定义 get_queryset 方法中以进行适当的过滤。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-12-15
        • 2019-12-18
        • 1970-01-01
        • 1970-01-01
        • 2021-06-21
        • 2020-12-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多