Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/app/static/doc/flask-docs/_sources/views.txt
diff options
context:
space:
mode:
Diffstat (limited to 'app/static/doc/flask-docs/_sources/views.txt')
-rw-r--r--app/static/doc/flask-docs/_sources/views.txt227
1 files changed, 227 insertions, 0 deletions
diff --git a/app/static/doc/flask-docs/_sources/views.txt b/app/static/doc/flask-docs/_sources/views.txt
new file mode 100644
index 0000000..441620a
--- /dev/null
+++ b/app/static/doc/flask-docs/_sources/views.txt
@@ -0,0 +1,227 @@
+.. _views:
+
+Pluggable Views
+===============
+
+.. versionadded:: 0.7
+
+Flask 0.7 introduces pluggable views inspired by the generic views from
+Django which are based on classes instead of functions. The main
+intention is that you can replace parts of the implementations and this
+way have customizable pluggable views.
+
+Basic Principle
+---------------
+
+Consider you have a function that loads a list of objects from the
+database and renders into a template::
+
+ @app.route('/users/')
+ def show_users(page):
+ users = User.query.all()
+ return render_template('users.html', users=users)
+
+This is simple and flexible, but if you want to provide this view in a
+generic fashion that can be adapted to other models and templates as well
+you might want more flexibility. This is where pluggable class based
+views come into place. As the first step to convert this into a class
+based view you would do this::
+
+
+ from flask.views import View
+
+ class ShowUsers(View):
+
+ def dispatch_request(self):
+ users = User.query.all()
+ return render_template('users.html', objects=users)
+
+ app.add_url_rule('/users/', ShowUsers.as_view('show_users'))
+
+As you can see what you have to do is to create a subclass of
+:class:`flask.views.View` and implement
+:meth:`~flask.views.View.dispatch_request`. Then we have to convert that
+class into an actual view function by using the
+:meth:`~flask.views.View.as_view` class method. The string you pass to
+that function is the name of the endpoint that view will then have. But
+this by itself is not helpful, so let's refactor the code a bit::
+
+
+ from flask.views import View
+
+ class ListView(View):
+
+ def get_template_name(self):
+ raise NotImplementedError()
+
+ def render_template(self, context):
+ return render_template(self.get_template_name(), **context)
+
+ def dispatch_request(self):
+ context = {'objects': self.get_objects()}
+ return self.render_template(context)
+
+ class UserView(ListView):
+
+ def get_template_name(self):
+ return 'users.html'
+
+ def get_objects(self):
+ return User.query.all()
+
+This of course is not that helpful for such a small example, but it's good
+enough to explain the basic principle. When you have a class based view
+the question comes up what `self` points to. The way this works is that
+whenever the request is dispatched a new instance of the class is created
+and the :meth:`~flask.views.View.dispatch_request` method is called with
+the parameters from the URL rule. The class itself is instanciated with
+the parameters passed to the :meth:`~flask.views.View.as_view` function.
+For instance you can write a class like this::
+
+ class RenderTemplateView(View):
+ def __init__(self, template_name):
+ self.template_name = template_name
+ def dispatch_request(self):
+ return render_template(self.template_name)
+
+And then you can register it like this::
+
+ app.add_url_rule('/about', view_func=RenderTemplateView.as_view(
+ 'about_page', template_name='about.html'))
+
+Method Hints
+------------
+
+Pluggable views are attached to the application like a regular function by
+either using :func:`~flask.Flask.route` or better
+:meth:`~flask.Flask.add_url_rule`. That however also means that you would
+have to provide the names of the HTTP methods the view supports when you
+attach this. In order to move that information to the class you can
+provide a :attr:`~flask.views.View.methods` attribute that has this
+information::
+
+ class MyView(View):
+ methods = ['GET', 'POST']
+
+ def dispatch_request(self):
+ if request.method == 'POST':
+ ...
+ ...
+
+ app.add_url_rule('/myview', view_func=MyView.as_view('myview'))
+
+Method Based Dispatching
+------------------------
+
+For RESTful APIs it's especially helpful to execute a different function
+for each HTTP method. With the :class:`flask.views.MethodView` you can
+easily do that. Each HTTP method maps to a function with the same name
+(just in lowercase)::
+
+ from flask.views import MethodView
+
+ class UserAPI(MethodView):
+
+ def get(self):
+ users = User.query.all()
+ ...
+
+ def post(self):
+ user = User.from_form_data(request.form)
+ ...
+
+ app.add_url_rule('/users/', view_func=UserAPI.as_view('users'))
+
+That way you also don't have to provide the
+:attr:`~flask.views.View.methods` attribute. It's automatically set based
+on the methods defined in the class.
+
+Decorating Views
+----------------
+
+Since the view class itself is not the view function that is added to the
+routing system it does not make much sense to decorate the class itself.
+Instead you either have to decorate the return value of
+:meth:`~flask.views.View.as_view` by hand::
+
+ view = rate_limited(UserAPI.as_view('users'))
+ app.add_url_rule('/users/', view_func=view)
+
+Starting with Flask 0.8 there is also an alternative way where you can
+specify a list of decorators to apply in the class declaration::
+
+ class UserAPI(MethodView):
+ decorators = [rate_limited]
+
+Due to the implicit self from the caller's perspective you cannot use
+regular view decorators on the individual methods of the view however,
+keep this in mind.
+
+Method Views for APIs
+---------------------
+
+Web APIs are often working very closely with HTTP verbs so it makes a lot
+of sense to implement such an API based on the
+:class:`~flask.views.MethodView`. That said, you will notice that the API
+will require different URL rules that go to the same method view most of
+the time. For instance consider that you are exposing a user object on
+the web:
+
+=============== =============== ======================================
+URL Method Description
+--------------- --------------- --------------------------------------
+``/users/`` ``GET`` Gives a list of all users
+``/users/`` ``POST`` Creates a new user
+``/users/<id>`` ``GET`` Shows a single user
+``/users/<id>`` ``PUT`` Updates a single user
+``/users/<id>`` ``DELETE`` Deletes a single user
+=============== =============== ======================================
+
+So how would you go about doing that with the
+:class:`~flask.views.MethodView`? The trick is to take advantage of the
+fact that you can provide multiple rules to the same view.
+
+Let's assume for the moment the view would look like this::
+
+ class UserAPI(MethodView):
+
+ def get(self, user_id):
+ if user_id is None:
+ # return a list of users
+ pass
+ else:
+ # expose a single user
+ pass
+
+ def post(self):
+ # create a new user
+ pass
+
+ def delete(self, user_id):
+ # delete a single user
+ pass
+
+ def put(self, user_id):
+ # update a single user
+ pass
+
+So how do we hook this up with the routing system? By adding two rules
+and explicitly mentioning the methods for each::
+
+ user_view = UserAPI.as_view('user_api')
+ app.add_url_rule('/users/', defaults={'user_id': None},
+ view_func=user_view, methods=['GET', 'POST'])
+ app.add_url_rule('/users/<int:user_id>', view_func=user_view,
+ methods=['GET', 'PUT', 'DELETE'])
+
+If you have a lot of APIs that look similar you can refactor that
+registration code::
+
+ def register_api(view, endpoint, url, pk='id', pk_type='int'):
+ view_func = view.as_view(endpoint)
+ app.add_url_rule(url, defaults={pk: None},
+ view_func=view_func, methods=['GET', 'POST'])
+ app.add_url_rule('%s<%s:%s>' % (url, pk), view_func=view_func,
+ methods=['GET', 'PUT', 'DELETE'])
+
+ register_api(UserAPI, 'user_api', '/users/', pk='user_id')