POST到一个资源的URL以创建另一个不同的资源

时间:2016-11-22 20:43:00

标签: django-rest-framework

在我的REST API中,我有两个实体:TestTestRun。我希望能够发送POST请求以创建TestRun(包含相应的TestRun字段),但此请求的网址必须为api/v1/test/{id}/start而不是api/v1/testrun 。 我知道使用@detail_route我可以自定义网址,但请求仍然会发送到api/v1/test/{id}

class TestViewSet(viewsets.ModelViewSet):
    queryset = Test.objects.all()
    serializer_class = TestSerializer

    @detail_route(methods=['post'], url_path='start')
    def start_test(self, request, pk=None):
        pass

class TestRunViewSet(viewsets.ModelViewSet):
    queryset = TestRun.objects.all()
    serializer_class = TestRunSerializer

这里可能需要一些高度定制的路由器?

1 个答案:

答案 0 :(得分:1)

好的,我有基本的例子。我认为你几乎没有问题,所以首先要做的事情是:

我的观点:

class TestViewSet(viewsets.ModelViewSet):
    queryset = Test.objects.all()
    serializer_class = TestSerializer

    @detail_route(methods=['post'], url_path='start', serializer_class=TestRunSerializer)
    def start_test(self, request, pk=None):
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            # add here TestRun object
            return Response(serializer.data, status=status.HTTP_200_OK)


class TestRunViewSet(viewsets.ModelViewSet):
    queryset = TestRun.objects.all()
    serializer_class = TestRunSerializer

我的网址:

router = SimpleRouter()
router.register('test', TestViewSet)
router.register('test-run', TestRunViewSet)

urlpatterns = router.urls

和设置网址:

urlpatterns = [
    url(r'^api/v1/', include('droute.urls'))
]

在这种情况下,您拥有Test和TestRun模型的完整CRUD - 一个在api / vi / test下,第二个在api / v1 / test-run中;

detail_route装饰器为您创建了额外的路线:/ api / v1 / test /:id / start

但这并不意味着api / v1 / test-run下的CRUD不再可访问。

如果你不想在api / v1 / test-run上不允许创建,你应该使用ReadOnlyModelViewSet作为TestRunViewSet的基础 - 这将只允许列表端点上的GET:api / v1 / test-run和在详细信息端点上:api / v1 / test-run //

你不需要在路由器中制造魔法 - 例如,SimpleRouter足以满足这种情况。

如果你想制作嵌套路由器,事情会变得更加复杂。你可以搜索stackoverflow - 有很多关于它的文章。但说实话,我会阻止你使用嵌套路由器,我从来没有觉得使用这是一种乐趣:)你可以在这里查看: https://github.com/alanjds/drf-nested-routers

我认为(但我有很少或没有信息),最好的API就是这样:

  • / api / v1 / test - > CREST for TEST
  • / api / v1 / test /:id / start - >开始测试POST
  • / api / v1 / test /:id / runs - >获取运行列表GET(TestViewSet或嵌套路由器上的list_route)
  • / api / v1 / test /:id / runs /:run_id - >获取运行详细信息GET(这是一个问题 - 因为它意味着您需要嵌套:(或附加到网址的一些自定义视图;)

快乐的编码,希望这有帮助。