Django REST Framework奇怪的结果

时间:2016-01-29 17:59:26

标签: python django django-rest-framework

出于某种原因,我在发送POST请求时遇到了一些奇怪的问题。

这是我的网址设置:

http://host/api/user/1/edit/
http://host/api/address/search/

其中/api/是API-Root,用户是模型,1是用户ID,editsearch是自定义函数。

这是views.py

class UserViewSet(viewsets.ModelViewSet):
    ...

    def post(self, request, pk, *args, **kwargs):
        ... (processing)

    @detail_route(methods=['post'])
    def edit(self, request, pk, *args, **kwargs):
        ... (processing)

class AddressViewSet(viewsets.ModelViewSet):
    ...

    def post(self, request, *args, **kwargs):
        ... (processing)

    @detail_route(methods=['post'])
    def search(self, request, *args, **kwargs):
        ... (processing)

这是urls.py

router = DefaultRouter()
router.register(r'user', views.UserViewSet)
router.register(r'address', views.AddressViewSet)

urlpatterns = [
    url(r'^', include(router.urls)),
    url(r'^authentication/', include('rest_framework.urls', namespace='rest_framework'))
]

我遇到的奇怪之处是:

如果我正在使用httpie并发送POST这样的编辑请求:

http POST http://host/api/user/1/edit/ name="john" address="google.com"

然后def post内的东西永远不会被执行。如果我让浏览器发送POST请求,则相同。

但是,如果我通过执行以下操作发送POST搜索请求:

http POST http://host/api/address/search/ name="john"

然后在这种情况下,def search中的内容将永远不会被执行,而只有def post内的内容才会被执行。

我能看到的唯一区别是,对于edit,还有pk(本例中为1的值),而没有{{1}对于`search。

有谁知道为什么会这样?这对我来说真的很混乱

2 个答案:

答案 0 :(得分:2)

在ViewSet中定义post()并不做任何事情,这适用于APIView派生类。如果要在ViewSet中覆盖默认对象创建,可以

def create(self, request, *args, **kwargs):
    ... do stuff ...

甚至更好

def perform_create(self, serializer):
    ... do stuff ...
    serializer.save()

至于地址,你需要使用list_route装饰器而不是detail_route。 detail_route用于操作单个对象,list_route用于列表。所以/ address / search /应该是list route和/ address / 1 / search /将是detail_route。请注意,我不认为post()中的代码在任何一种情况下运行。

以下是相关的文档http://www.django-rest-framework.org/api-guide/viewsets/#marking-extra-actions-for-routing

答案 1 :(得分:1)

当向休息框架提交帖子请求时,请求被映射到ViewSet上的方法,而不像简单地调用post方法的Django视图。

发布到user/{pk}/时,您的请求会映射到UserViewSet.create方法。发送到user/{pk}/edit/的帖子请求映射到您的UserViewSet.edit方法。在这两种情况下,都不会调用UserViewSet.post

似乎当您发布到不存在的自定义网址时,会调用post方法(可能作为后备)。在您的情况下,address/search/不是有效的网址,而是您已将端点定义为address/{pk}/search/

如果您想访问address/search/,则需要更新搜索方法,以使用list_route装饰器代替detail_route

class AddressViewSet(viewsets.ModelViewSet):
    ...

    @list_route(methods=['post'])
    def search(self, request, *args, **kwargs):
        ... (processing)

希望这有助于为您解决问题。