Fleshing out viewsets/routers · encode/django-rest-framework@c785628 (original) (raw)

1

``

`-

Not properly implemented yet, just the basic idea

`

2

``

-

3

``

-

4

``

`-

class BaseRouter(object):

`

5

``

`-

def init(self):

`

6

``

`-

self.resources = []

`

7

``

-

8

``

`-

def register(self, name, resource):

`

9

``

`-

self.resources.append((name, resource))

`

10

``

-

11

``

`-

@property

`

12

``

`-

def urlpatterns(self):

`

13

``

`-

ret = []

`

14

``

-

15

``

`-

for name, resource in self.resources:

`

16

``

`-

list_actions = {

`

17

``

`-

'get': getattr(resource, 'list', None),

`

18

``

`-

'post': getattr(resource, 'create', None)

`

19

``

`-

}

`

20

``

`-

detail_actions = {

`

21

``

`-

'get': getattr(resource, 'retrieve', None),

`

22

``

`-

'put': getattr(resource, 'update', None),

`

23

``

`-

'delete': getattr(resource, 'destroy', None)

`

24

``

`-

}

`

25

``

`-

list_regex = r'^%s/$' % name

`

26

``

`-

detail_regex = r'^%s/(?P[0-9]+)/$' % name

`

27

``

`-

list_name = '%s-list'

`

28

``

`-

detail_name = '%s-detail'

`

29

``

-

30

``

`-

ret += url(list_regex, resource.as_view(list_actions), list_name)

`

31

``

`-

ret += url(detail_regex, resource.as_view(detail_actions), detail_name)

`

32

``

-

33

``

`-

return ret

`

``

1

`+

from functools import update_wrapper

`

``

2

`+

from django.utils.decorators import classonlymethod

`

``

3

`+

from rest_framework import views, generics, mixins

`

``

4

+

``

5

+

``

6

`+

class ViewSetMixin(object):

`

``

7

`+

"""

`

``

8

`+

This is the magic.

`

``

9

+

``

10

`` +

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

``

``

11

`+

the binding of HTTP methods to actions on the Resource.

`

``

12

+

``

13

`+

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

`

``

14

`+

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

`

``

15

+

``

16

`+

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

`

``

17

`+

"""

`

``

18

+

``

19

`+

@classonlymethod

`

``

20

`+

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

`

``

21

`+

"""

`

``

22

`+

Main entry point for a request-response process.

`

``

23

+

``

24

`+

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

`

``

25

`` +

instantiated view, we need to totally reimplement .as_view,

``

``

26

`+

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

`

``

27

`+

"""

`

``

28

`+

sanitize keyword arguments

`

``

29

`+

for key in initkwargs:

`

``

30

`+

if key in cls.http_method_names:

`

``

31

`+

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

`

``

32

`+

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

`

``

33

`+

% (key, cls.name))

`

``

34

`+

if not hasattr(cls, key):

`

``

35

`+

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

`

``

36

`+

cls.name, key))

`

``

37

+

``

38

`+

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

`

``

39

`+

self = cls(**initkwargs)

`

``

40

+

``

41

`+

Bind methods to actions

`

``

42

`+

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

`

``

43

`+

for method, action in actions.items():

`

``

44

`+

handler = getattr(self, action)

`

``

45

`+

setattr(self, method, handler)

`

``

46

+

``

47

`+

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

`

``

48

`+

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

`

``

49

`+

self.head = self.get

`

``

50

+

``

51

`+

And continue as usual

`

``

52

`+

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

`

``

53

+

``

54

`+

take name and docstring from class

`

``

55

`+

update_wrapper(view, cls, updated=())

`

``

56

+

``

57

`+

and possible attributes set by decorators

`

``

58

`+

like csrf_exempt from dispatch

`

``

59

`+

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

`

``

60

`+

return view

`

``

61

+

``

62

+

``

63

`+

class ViewSet(ViewSetMixin, views.APIView):

`

``

64

`+

pass

`

``

65

+

``

66

+

``

67

`+

Note the inheritence of both MultipleObjectAPIView and SingleObjectAPIView

`

``

68

`+

is a bit weird given the diamond inheritence, but it will work for now.

`

``

69

`+

There's some implementation clean up that can happen later.

`

``

70

`+

class ModelViewSet(mixins.CreateModelMixin,

`

``

71

`+

mixins.RetrieveModelMixin,

`

``

72

`+

mixins.UpdateModelMixin,

`

``

73

`+

mixins.DestroyModelMixin,

`

``

74

`+

mixins.ListModelMixin,

`

``

75

`+

ViewSetMixin,

`

``

76

`+

generics.MultipleObjectAPIView,

`

``

77

`+

generics.SingleObjectAPIView):

`

``

78

`+

pass

`

``

79

+

``

80

+

``

81

`+

class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,

`

``

82

`+

mixins.ListModelMixin,

`

``

83

`+

ViewSetMixin,

`

``

84

`+

generics.MultipleObjectAPIView,

`

``

85

`+

generics.SingleObjectAPIView):

`

``

86

`+

pass

`