Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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