出于某种原因,我在发送POST
请求时遇到了一些奇怪的问题。
这是我的网址设置:
http://host/api/user/1/edit/
http://host/api/address/search/
其中/api/
是API-Root,用户是模型,1是用户ID,edit
和search
是自定义函数。
这是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。
有谁知道为什么会这样?这对我来说真的很混乱
答案 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)
希望这有助于为您解决问题。