2017-04-20 98 views
2

PUTPATCH都是同一个mixin的一部分(UpdateModelMixin)。如何不允许PUT方法,但允许在DRF ViewSet中使用PATCH?

所以,如果我延长它像这样:

class UserViewSet(mixins.UpdateModelMixin, GenericViewSet): 
    queryset = User.objects.all() 
    serializer_class = UserSerializer 

两个PUTPATCH是允许的。我不想为我的应用程序允许PUT(因为PATCH已经完成了这项工作,并且我想仅使用POST限制对象创建)。一种方法是创建权限:

class NoPut(permissions.BasePermission): 
    """ 
    PUT not allowed. 
    """ 
    message = 'You do not have permission to complete the action you are trying to perform.' 

    def has_object_permission(self, request, view, obj): 
     if view.action == "update": 
      return False 
     return True 

而且给这个权限我所有的ViewSets允许PATCH。这是做这件事的最好方法吗?有更好的方法吗?

编辑:查看由@wim提供的答案后,将本是一个精解(保留一切除了put映射相同移除):

from rest_framework.routers import SimpleRouter 
class NoPutRouter(SimpleRouter): 

    routes = [ 
     # List route. 
     Route(
      url=r'^{prefix}{trailing_slash}$', 
      mapping={ 
       'get': 'list', 
       'post': 'create' 
      }, 
      name='{basename}-list', 
      initkwargs={'suffix': 'List'} 
     ), 
     # Dynamically generated list routes. 
     # Generated using @list_route decorator 
     # on methods of the viewset. 
     DynamicListRoute(
      url=r'^{prefix}/{methodname}{trailing_slash}$', 
      name='{basename}-{methodnamehyphen}', 
      initkwargs={} 
     ), 
     # Detail route. 
     Route(
      url=r'^{prefix}/{lookup}{trailing_slash}$', 
      mapping={ 
       'get': 'retrieve', 
       # put removed 
       'patch': 'partial_update', 
       'delete': 'destroy' 
      }, 
      name='{basename}-detail', 
      initkwargs={'suffix': 'Instance'} 
     ), 
     # Dynamically generated detail routes. 
     # Generated using @detail_route decorator on methods of the viewset. 
     DynamicDetailRoute(
      url=r'^{prefix}/{lookup}/{methodname}{trailing_slash}$', 
      name='{basename}-{methodnamehyphen}', 
      initkwargs={} 
     ), 
    ] 

或我需要重新定义其他方法在SimpleRoute(例如__init()__,get_routes(),_get_dynamic_routes(),get_method_map()等)为了使它正常工作?

回答

2

而不是使用mixins.UpdateModelMixin只是定义自己的mixin,将只执行补丁:

class UpdateModelMixin(object): 
    """ 
    Update a model instance. 
    """ 
    def partial_update(self, request, *args, **kwargs): 
     partial = True 
     instance = self.get_object() 
     serializer = self.get_serializer(instance, data=request.data, partial=partial) 
     serializer.is_valid(raise_exception=True) 
     self.perform_update(serializer) 

     if getattr(instance, '_prefetched_objects_cache', None): 
      # If 'prefetch_related' has been applied to a queryset, we need to 
      # forcibly invalidate the prefetch cache on the instance. 
      instance._prefetched_objects_cache = {} 

     return Response(serializer.data) 

    def perform_update(self, serializer): 
     serializer.save() 
1

我认为一个优越的解决方案是使用自定义router并禁用PUT的路由。然后使用您的自定义路由器查看视图。

class SimpleRouter(BaseRouter): 
    routes = [ 
     # List route. 
     Route(
      url=r'^{prefix}{trailing_slash}$', 
      mapping={ 
       'get': 'list', 
       'post': 'create' 
      }, 
      name='{basename}-list', 
      initkwargs={'suffix': 'List'} 
     ), 
     # Dynamically generated list routes. 
     # Generated using @list_route decorator 
     # on methods of the viewset. 
     DynamicListRoute(
      url=r'^{prefix}/{methodname}{trailing_slash}$', 
      name='{basename}-{methodnamehyphen}', 
      initkwargs={} 
     ), 
     # Detail route. 
     Route(
      url=r'^{prefix}/{lookup}{trailing_slash}$', 
      mapping={ 
       'get': 'retrieve', 
       'put': 'update', 
       'patch': 'partial_update', 
       'delete': 'destroy' 
      }, 
      name='{basename}-detail', 
      initkwargs={'suffix': 'Instance'} 
     ), 
     # Dynamically generated detail routes. 
     # Generated using @detail_route decorator on methods of the viewset. 
     DynamicDetailRoute(
      url=r'^{prefix}/{lookup}/{methodname}{trailing_slash}$', 
      name='{basename}-{methodnamehyphen}', 
      initkwargs={} 
     ), 
    ] 

^路由器的实现看起来像这样。所以你只需要继承SimpleRouter或者DefaultRouter,并且定义你想要的类的属性routes。您可以完全删除Route(mapping={...})中'放入'的映射,或者您可以定义自己的操作来处理它,并返回适当的400点声音。

+0

感谢。好吧,我编辑了我的答案,包括新的自定义路由器。你可以验证它是一个好的自定义路由器,还是我需要重新定义'SimpleRouter'中的其他方法才能正常工作? – user2719875

相关问题