From 3d4bb4b5533fa281c2f11c12ceb0a9ae61aa0d54 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 21 Jun 2013 22:03:07 +0100 Subject: Ensure action kwargs properly handdled. Refs #940. --- htmlcov/rest_framework_viewsets.html | 359 +++++++++++++++++++++++++++++++++++ 1 file changed, 359 insertions(+) create mode 100644 htmlcov/rest_framework_viewsets.html (limited to 'htmlcov/rest_framework_viewsets.html') diff --git a/htmlcov/rest_framework_viewsets.html b/htmlcov/rest_framework_viewsets.html new file mode 100644 index 00000000..8264ddc0 --- /dev/null +++ b/htmlcov/rest_framework_viewsets.html @@ -0,0 +1,359 @@ + + + + + + + + Coverage for rest_framework/viewsets: 95% + + + + + + + + + + + +
+ +

Hot-keys on this page

+
+

+ r + m + x + p   toggle line displays +

+

+ j + k   next/prev highlighted chunk +

+

+ 0   (zero) top of page +

+

+ 1   (one) first highlighted chunk +

+
+
+ +
+ + + + + +
+

1

+

2

+

3

+

4

+

5

+

6

+

7

+

8

+

9

+

10

+

11

+

12

+

13

+

14

+

15

+

16

+

17

+

18

+

19

+

20

+

21

+

22

+

23

+

24

+

25

+

26

+

27

+

28

+

29

+

30

+

31

+

32

+

33

+

34

+

35

+

36

+

37

+

38

+

39

+

40

+

41

+

42

+

43

+

44

+

45

+

46

+

47

+

48

+

49

+

50

+

51

+

52

+

53

+

54

+

55

+

56

+

57

+

58

+

59

+

60

+

61

+

62

+

63

+

64

+

65

+

66

+

67

+

68

+

69

+

70

+

71

+

72

+

73

+

74

+

75

+

76

+

77

+

78

+

79

+

80

+

81

+

82

+

83

+

84

+

85

+

86

+

87

+

88

+

89

+

90

+

91

+

92

+

93

+

94

+

95

+

96

+

97

+

98

+

99

+

100

+

101

+

102

+

103

+

104

+

105

+

106

+

107

+

108

+

109

+

110

+

111

+

112

+

113

+

114

+

115

+

116

+

117

+

118

+

119

+

120

+

121

+

122

+

123

+

124

+

125

+

126

+

127

+

128

+

129

+

130

+

131

+

132

+

133

+

134

+

135

+

136

+

137

+

138

+

139

+ +
+

""" 

+

ViewSets are essentially just a type of class based view, that doesn't provide 

+

any method handlers, such as `get()`, `post()`, etc... but instead has actions, 

+

such as `list()`, `retrieve()`, `create()`, etc... 

+

 

+

Actions are only bound to methods at the point of instantiating the views. 

+

 

+

    user_list = UserViewSet.as_view({'get': 'list'}) 

+

    user_detail = UserViewSet.as_view({'get': 'retrieve'}) 

+

 

+

Typically, rather than instantiate views from viewsets directly, you'll 

+

regsiter the viewset with a router and let the URL conf be determined 

+

automatically. 

+

 

+

    router = DefaultRouter() 

+

    router.register(r'users', UserViewSet, 'user') 

+

    urlpatterns = router.urls 

+

""" 

+

from __future__ import unicode_literals 

+

 

+

from functools import update_wrapper 

+

from django.utils.decorators import classonlymethod 

+

from rest_framework import views, generics, mixins 

+

 

+

 

+

class ViewSetMixin(object): 

+

    """ 

+

    This is the magic. 

+

 

+

    Overrides `.as_view()` so that it takes an `actions` keyword that performs 

+

    the binding of HTTP methods to actions on the Resource. 

+

 

+

    For example, to create a concrete view binding the 'GET' and 'POST' methods 

+

    to the 'list' and 'create' actions... 

+

 

+

    view = MyViewSet.as_view({'get': 'list', 'post': 'create'}) 

+

    """ 

+

 

+

    @classonlymethod 

+

    def as_view(cls, actions=None, **initkwargs): 

+

        """ 

+

        Because of the way class based views create a closure around the 

+

        instantiated view, we need to totally reimplement `.as_view`, 

+

        and slightly modify the view function that is created and returned. 

+

        """ 

+

        # The suffix initkwarg is reserved for identifing the viewset type 

+

        # eg. 'List' or 'Instance'. 

+

        cls.suffix = None 

+

 

+

        # sanitize keyword arguments 

+

        for key in initkwargs: 

+

            if key in cls.http_method_names: 

+

                raise TypeError("You tried to pass in the %s method name as a " 

+

                                "keyword argument to %s(). Don't do that." 

+

                                % (key, cls.__name__)) 

+

            if not hasattr(cls, key): 

+

                raise TypeError("%s() received an invalid keyword %r" % ( 

+

                    cls.__name__, key)) 

+

 

+

        def view(request, *args, **kwargs): 

+

            self = cls(**initkwargs) 

+

            # We also store the mapping of request methods to actions, 

+

            # so that we can later set the action attribute. 

+

            # eg. `self.action = 'list'` on an incoming GET request. 

+

            self.action_map = actions 

+

 

+

            # Bind methods to actions 

+

            # This is the bit that's different to a standard view 

+

            for method, action in actions.items(): 

+

                handler = getattr(self, action) 

+

                setattr(self, method, handler) 

+

 

+

            # Patch this in as it's otherwise only present from 1.5 onwards 

+

            if hasattr(self, 'get') and not hasattr(self, 'head'): 

+

                self.head = self.get 

+

 

+

            # And continue as usual 

+

            return self.dispatch(request, *args, **kwargs) 

+

 

+

        # take name and docstring from class 

+

        update_wrapper(view, cls, updated=()) 

+

 

+

        # and possible attributes set by decorators 

+

        # like csrf_exempt from dispatch 

+

        update_wrapper(view, cls.dispatch, assigned=()) 

+

 

+

        # We need to set these on the view function, so that breadcrumb 

+

        # generation can pick out these bits of information from a 

+

        # resolved URL. 

+

        view.cls = cls 

+

        view.suffix = initkwargs.get('suffix', None) 

+

        return view 

+

 

+

    def initialize_request(self, request, *args, **kargs): 

+

        """ 

+

        Set the `.action` attribute on the view, 

+

        depending on the request method. 

+

        """ 

+

        request = super(ViewSetMixin, self).initialize_request(request, *args, **kargs) 

+

        self.action = self.action_map.get(request.method.lower()) 

+

        return request 

+

 

+

 

+

class ViewSet(ViewSetMixin, views.APIView): 

+

    """ 

+

    The base ViewSet class does not provide any actions by default. 

+

    """ 

+

    pass 

+

 

+

 

+

class GenericViewSet(ViewSetMixin, generics.GenericAPIView): 

+

    """ 

+

    The GenericViewSet class does not provide any actions by default, 

+

    but does include the base set of generic view behavior, such as 

+

    the `get_object` and `get_queryset` methods. 

+

    """ 

+

    pass 

+

 

+

 

+

class ReadOnlyModelViewSet(mixins.RetrieveModelMixin, 

+

                           mixins.ListModelMixin, 

+

                           GenericViewSet): 

+

    """ 

+

    A viewset that provides default `list()` and `retrieve()` actions. 

+

    """ 

+

    pass 

+

 

+

 

+

class ModelViewSet(mixins.CreateModelMixin, 

+

                    mixins.RetrieveModelMixin, 

+

                    mixins.UpdateModelMixin, 

+

                    mixins.DestroyModelMixin, 

+

                    mixins.ListModelMixin, 

+

                    GenericViewSet): 

+

    """ 

+

    A viewset that provides default `create()`, `retrieve()`, `update()`, 

+

    `partial_update()`, `destroy()` and `list()` actions. 

+

    """ 

+

    pass 

+ +
+
+ + + + + -- cgit v1.2.3