Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 151 lines (120 sloc) 5.61 kb
dcf2198 @mitsuhiko Added class based views
authored
1 # -*- coding: utf-8 -*-
2 """
3 flask.views
4 ~~~~~~~~~~~
5
4aebc26 Hyphenate "class-based"
FND authored
6 This module provides class-based views inspired by the ones in Django.
dcf2198 @mitsuhiko Added class based views
authored
7
8 :copyright: (c) 2011 by Armin Ronacher.
9 :license: BSD, see LICENSE for more details.
10 """
11 from .globals import request
12
13
14 http_method_funcs = frozenset(['get', 'post', 'head', 'options',
c5ebf9a @jfinkels Added PATCH method to the list of HTTP method functions for use in th…
jfinkels authored
15 'delete', 'put', 'trace', 'patch'])
dcf2198 @mitsuhiko Added class based views
authored
16
17
18 class View(object):
19 """Alternative way to use view functions. A subclass has to implement
20 :meth:`dispatch_request` which is called with the view arguments from
21 the URL routing system. If :attr:`methods` is provided the methods
22 do not have to be passed to the :meth:`~flask.Flask.add_url_rule`
23 method explicitly::
24
25 class MyView(View):
26 methods = ['GET']
27
28 def dispatch_request(self, name):
29 return 'Hello %s!' % name
30
31 app.add_url_rule('/hello/<name>', view_func=MyView.as_view('myview'))
ef0f626 @mitsuhiko Added flask.views.View.decorators to automatically decorate class bas…
authored
32
33 When you want to decorate a pluggable view you will have to either do that
34 when the view function is created (by wrapping the return value of
35 :meth:`as_view`) or you can use the :attr:`decorators` attribute::
36
37 class SecretView(View):
38 methods = ['GET']
39 decorators = [superuser_required]
40
41 def dispatch_request(self):
42 ...
43
44 The decorators stored in the decorators list are applied one after another
45 when the view function is created. Note that you can *not* use the class
46 based decorators since those would decorate the view class and not the
47 generated view function!
dcf2198 @mitsuhiko Added class based views
authored
48 """
49
ef0f626 @mitsuhiko Added flask.views.View.decorators to automatically decorate class bas…
authored
50 #: A for which methods this pluggable view can handle.
dcf2198 @mitsuhiko Added class based views
authored
51 methods = None
52
4aebc26 Hyphenate "class-based"
FND authored
53 #: The canonical way to decorate class-based views is to decorate the
ef0f626 @mitsuhiko Added flask.views.View.decorators to automatically decorate class bas…
authored
54 #: return value of as_view(). However since this moves parts of the
55 #: logic from the class declaration to the place where it's hooked
56 #: into the routing system.
57 #:
58 #: You can place one or more decorators in this list and whenever the
59 #: view function is created the result is automatically decorated.
60 #:
61 #: .. versionadded:: 0.8
62 decorators = []
63
dcf2198 @mitsuhiko Added class based views
authored
64 def dispatch_request(self):
775caf7 @mitsuhiko Improved cbv and added tests
authored
65 """Subclasses have to override this method to implement the
17a46a4 @jperras Fixed typo in docstring of `dispatch_request` method of `flask.views.…
jperras authored
66 actual view function code. This method is called with all
775caf7 @mitsuhiko Improved cbv and added tests
authored
67 the arguments from the URL rule.
68 """
dcf2198 @mitsuhiko Added class based views
authored
69 raise NotImplementedError()
70
71 @classmethod
72 def as_view(cls, name, *class_args, **class_kwargs):
2792dcf simplified as_view documentation
FND authored
73 """Converts the class into an actual view function that can be used
74 with the routing system. Internally this generates a function on the
75 fly which will instantiate the :class:`View` on each request and call
76 the :meth:`dispatch_request` method on it.
dcf2198 @mitsuhiko Added class based views
authored
77
78 The arguments passed to :meth:`as_view` are forwarded to the
79 constructor of the class.
80 """
81 def view(*args, **kwargs):
775caf7 @mitsuhiko Improved cbv and added tests
authored
82 self = view.view_class(*class_args, **class_kwargs)
dcf2198 @mitsuhiko Added class based views
authored
83 return self.dispatch_request(*args, **kwargs)
ef0f626 @mitsuhiko Added flask.views.View.decorators to automatically decorate class bas…
authored
84
85 if cls.decorators:
86 view.__name__ = name
87 view.__module__ = cls.__module__
88 for decorator in cls.decorators:
89 view = decorator(view)
90
775caf7 @mitsuhiko Improved cbv and added tests
authored
91 # we attach the view class to the view function for two reasons:
4aebc26 Hyphenate "class-based"
FND authored
92 # first of all it allows us to easily figure out what class-based
76c1a1f fixed spelling of "instantiate"
FND authored
93 # view this thing came from, secondly it's also used for instantiating
775caf7 @mitsuhiko Improved cbv and added tests
authored
94 # the view class so you can actually replace it with something else
95 # for testing purposes and debugging.
96 view.view_class = cls
dcf2198 @mitsuhiko Added class based views
authored
97 view.__name__ = name
98 view.__doc__ = cls.__doc__
99 view.__module__ = cls.__module__
100 view.methods = cls.methods
101 return view
102
103
104 class MethodViewType(type):
105
106 def __new__(cls, name, bases, d):
107 rv = type.__new__(cls, name, bases, d)
775caf7 @mitsuhiko Improved cbv and added tests
authored
108 if 'methods' not in d:
109 methods = set(rv.methods or [])
bb99158 Remove an unused iteration variable.
Jon Parise authored
110 for key in d:
dcf2198 @mitsuhiko Added class based views
authored
111 if key in http_method_funcs:
775caf7 @mitsuhiko Improved cbv and added tests
authored
112 methods.add(key.upper())
dcf2198 @mitsuhiko Added class based views
authored
113 # if we have no method at all in there we don't want to
114 # add a method list. (This is for instance the case for
115 # the baseclass or another subclass of a base method view
116 # that does not introduce new methods).
117 if methods:
775caf7 @mitsuhiko Improved cbv and added tests
authored
118 rv.methods = sorted(methods)
dcf2198 @mitsuhiko Added class based views
authored
119 return rv
120
121
122 class MethodView(View):
4aebc26 Hyphenate "class-based"
FND authored
123 """Like a regular class-based view but that dispatches requests to
dcf2198 @mitsuhiko Added class based views
authored
124 particular methods. For instance if you implement a method called
125 :meth:`get` it means you will response to ``'GET'`` requests and
126 the :meth:`dispatch_request` implementation will automatically
127 forward your request to that. Also :attr:`options` is set for you
128 automatically::
129
130 class CounterAPI(MethodView):
131
132 def get(self):
133 return session.get('counter', 0)
134
135 def post(self):
136 session['counter'] = session.get('counter', 0) + 1
137 return 'OK'
138
139 app.add_url_rule('/counter', view_func=CounterAPI.as_view('counter'))
140 """
141 __metaclass__ = MethodViewType
142
143 def dispatch_request(self, *args, **kwargs):
144 meth = getattr(self, request.method.lower(), None)
32c7e43 @mitsuhiko Simplified HEAD handling for method views
authored
145 # if the request method is HEAD and we don't have a handler for it
146 # retry with GET
147 if meth is None and request.method == 'HEAD':
148 meth = getattr(self, 'get', None)
a59cbd4 @plaes Minor grammar fix
plaes authored
149 assert meth is not None, 'Unimplemented method %r' % request.method
dcf2198 @mitsuhiko Added class based views
authored
150 return meth(*args, **kwargs)
Something went wrong with that request. Please try again.