/rest_framework/decorators.py

https://github.com/mhsparks/django-rest-framework · Python · 129 lines · 71 code · 32 blank · 26 comment · 4 complexity · 5647eca88654957b8b39b11fb42a28a7 MD5 · raw file

  1. """
  2. The most important decorator in this module is `@api_view`, which is used
  3. for writing function-based views with REST framework.
  4. There are also various decorators for setting the API policies on function
  5. based views, as well as the `@action` and `@link` decorators, which are
  6. used to annotate methods on viewsets that should be included by routers.
  7. """
  8. from __future__ import unicode_literals
  9. from rest_framework.compat import six
  10. from rest_framework.views import APIView
  11. import types
  12. def api_view(http_method_names):
  13. """
  14. Decorator that converts a function-based view into an APIView subclass.
  15. Takes a list of allowed methods for the view as an argument.
  16. """
  17. def decorator(func):
  18. WrappedAPIView = type(
  19. six.PY3 and 'WrappedAPIView' or b'WrappedAPIView',
  20. (APIView,),
  21. {'__doc__': func.__doc__}
  22. )
  23. # Note, the above allows us to set the docstring.
  24. # It is the equivalent of:
  25. #
  26. # class WrappedAPIView(APIView):
  27. # pass
  28. # WrappedAPIView.__doc__ = func.doc <--- Not possible to do this
  29. # api_view applied without (method_names)
  30. assert not(isinstance(http_method_names, types.FunctionType)), \
  31. '@api_view missing list of allowed HTTP methods'
  32. # api_view applied with eg. string instead of list of strings
  33. assert isinstance(http_method_names, (list, tuple)), \
  34. '@api_view expected a list of strings, received %s' % type(http_method_names).__name__
  35. allowed_methods = set(http_method_names) | set(('options',))
  36. WrappedAPIView.http_method_names = [method.lower() for method in allowed_methods]
  37. def handler(self, *args, **kwargs):
  38. return func(*args, **kwargs)
  39. for method in http_method_names:
  40. setattr(WrappedAPIView, method.lower(), handler)
  41. WrappedAPIView.__name__ = func.__name__
  42. WrappedAPIView.renderer_classes = getattr(func, 'renderer_classes',
  43. APIView.renderer_classes)
  44. WrappedAPIView.parser_classes = getattr(func, 'parser_classes',
  45. APIView.parser_classes)
  46. WrappedAPIView.authentication_classes = getattr(func, 'authentication_classes',
  47. APIView.authentication_classes)
  48. WrappedAPIView.throttle_classes = getattr(func, 'throttle_classes',
  49. APIView.throttle_classes)
  50. WrappedAPIView.permission_classes = getattr(func, 'permission_classes',
  51. APIView.permission_classes)
  52. return WrappedAPIView.as_view()
  53. return decorator
  54. def renderer_classes(renderer_classes):
  55. def decorator(func):
  56. func.renderer_classes = renderer_classes
  57. return func
  58. return decorator
  59. def parser_classes(parser_classes):
  60. def decorator(func):
  61. func.parser_classes = parser_classes
  62. return func
  63. return decorator
  64. def authentication_classes(authentication_classes):
  65. def decorator(func):
  66. func.authentication_classes = authentication_classes
  67. return func
  68. return decorator
  69. def throttle_classes(throttle_classes):
  70. def decorator(func):
  71. func.throttle_classes = throttle_classes
  72. return func
  73. return decorator
  74. def permission_classes(permission_classes):
  75. def decorator(func):
  76. func.permission_classes = permission_classes
  77. return func
  78. return decorator
  79. def link(**kwargs):
  80. """
  81. Used to mark a method on a ViewSet that should be routed for GET requests.
  82. """
  83. def decorator(func):
  84. func.bind_to_methods = ['get']
  85. func.kwargs = kwargs
  86. return func
  87. return decorator
  88. def action(methods=['post'], **kwargs):
  89. """
  90. Used to mark a method on a ViewSet that should be routed for POST requests.
  91. """
  92. def decorator(func):
  93. func.bind_to_methods = methods
  94. func.kwargs = kwargs
  95. return func
  96. return decorator