Class-based views¶
Group related views into a class for easier management.
-
coaster.views.classview.
rulejoin
(class_rule, method_rule)[source]¶ Join class and method rules. Used internally by
ClassView
to combine rules from theroute()
decorators on the class and on the individual view handler methods:>>> rulejoin('/', '') '/' >>> rulejoin('/', 'first') '/first' >>> rulejoin('/first', '/second') '/second' >>> rulejoin('/first', 'second') '/first/second' >>> rulejoin('/first/', 'second') '/first/second' >>> rulejoin('/first/<second>', '') '/first/<second>' >>> rulejoin('/first/<second>', 'third') '/first/<second>/third'
-
coaster.views.classview.
current_view
= None¶ A proxy object that holds the currently executing
ClassView
instance, for use in templates as context. Exposed to templates bycoaster.app.init_app()
. Note that the current view handler method within the class is namedcurrent_handler
, so to examine it, usecurrent_view.current_handler
.
-
class
coaster.views.classview.
ClassView
[source]¶ Base class for defining a collection of views that are related to each other. Subclasses may define methods decorated with
route()
. Wheninit_app()
is called, these will be added as routes to the app.Typical use:
@route('/') class IndexView(ClassView): @viewdata(title="Homepage") @route('') def index(): return render_template('index.html.jinja2') @route('about') @viewdata(title="About us") def about(): return render_template('about.html.jinja2') IndexView.init_app(app)
The
route()
decorator on the class specifies the base rule, which is prefixed to the rule specified on each view method. This example produces two view handlers, for/
and/about
. Multipleroute()
decorators may be used in both places.The
viewdata()
decorator can be used to specify additional data, and may appear either before or after theroute()
decorator, but only adjacent to it. Data specified here is available as thedata
attribute on the view handler, or at runtime in templates ascurrent_view.current_handler.data
.A rudimentary CRUD view collection can be assembled like this:
@route('/doc/<name>') class DocumentView(ClassView): @route('') @render_with('mydocument.html.jinja2', json=True) def view(self, name): document = MyDocument.query.filter_by(name=name).first_or_404() return document.current_access() @route('edit', methods=['POST']) @requestform('title', 'content') def edit(self, name, title, content): document = MyDocument.query.filter_by(name=name).first_or_404() document.title = title document.content = content return 'edited!' DocumentView.init_app(app)
See
ModelView
for a better way to build views around a model.-
classmethod
add_route_for
(_name, rule, **options)[source]¶ Add a route for an existing method or view. Useful for modifying routes that a subclass inherits from a base class:
class BaseView(ClassView): def latent_view(self): return 'latent-view' @route('other') def other_view(self): return 'other-view' @route('/path') class SubView(BaseView): pass SubView.add_route_for('latent_view', 'latent') SubView.add_route_for('other_view', 'another') SubView.init_app(app) # Created routes: # /path/latent -> SubView.latent (added) # /path/other -> SubView.other (inherited) # /path/another -> SubView.other (added)
Parameters: - _name – Name of the method or view on the class
- rule – URL rule to be added
- options – Additional options for
add_url_rule()
-
after_request
(response)[source]¶ This method is called with the response from the view handler method. It must return a valid response object. Subclasses and mixin classes may override this to perform any necessary post-processing:
class MyView(ClassView): ... def after_request(self, response): response = super().after_request(response) ... # Process here return response
Parameters: response – Response from the view handler method Returns: Response object
-
before_request
()[source]¶ This method is called after the app’s
before_request
handlers, and before the class’s view method. Subclasses and mixin classes may define their ownbefore_request()
to pre-process requests. This method receives context via self, in particular viacurrent_handler
andview_args
.
-
current_handler
= None¶ When a view is called, this will point to the current view handler, an instance of
ViewHandler
.
-
dispatch_request
(view, view_args)[source]¶ View dispatcher that calls before_request, the view, and then after_request. Subclasses may override this to provide a custom flow.
ModelView
does this to insert a model loading phase.Parameters: - view – View method wrapped in specified decorators. The dispatcher must call this
- view_args (dict) – View arguments, to be passed on to the view method
-
classmethod
init_app
(app, callback=None)[source]¶ Register views on an app. If
callback
is specified, it will be called afterapp.
add_url_rule()
, with the same parameters.
-
is_always_available
= False¶ Indicates whether meth:is_available should simply return True without conducting a test. Subclasses should not set this flag. It will be set by
init_app()
if any view handler is missing anis_available
method, as it implies that view is always available.
-
is_available
()[source]¶ Returns True if any view handler in the class is currently available via its is_available method.
-
view_args
= None¶ When a view is called, this will be replaced with a dictionary of arguments to the view.
-
classmethod
-
class
coaster.views.classview.
ModelView
(obj=None)[source]¶ Base class for constructing views around a model. Functionality is provided via mixin classes that must precede
ModelView
in base class order. Two mixins are provided:UrlForView
andInstanceLoader
. Sample use:@route('/doc/<document>') class DocumentView(UrlForView, InstanceLoader, ModelView): model = Document route_model_map = { 'document': 'name' } @route('') @render_with(json=True) def view(self): return self.obj.current_access() Document.views.main = DocumentView DocumentView.init_app(app)
Views will not receive view arguments, unlike in
ClassView
. If necessary, they are available as self.view_args.-
dispatch_request
(view, view_args)[source]¶ View dispatcher that calls
before_request()
,loader()
,after_loader()
, the view, and thenafter_request()
.Parameters: - view – View method wrapped in specified decorators.
- view_args (dict) – View arguments, to be passed on to the view method
-
loader
(**view_args)[source]¶ Subclasses or mixin classes may override this method to provide a model instance loader. The return value of this method will be placed at
self.obj
.Returns: Object instance loaded from database
-
model
= None¶ The model that this view class represents, to be specified by subclasses.
-
query
= None¶ A base query to use if the model needs special handling.
-
route_model_map
= {}¶ A mapping of URL rule variables to attributes on the model. For example, if the URL rule is
/<parent>/<document>
, the attribute map can be:model = MyModel route_model_map = { 'document': 'name', # Map 'document' in URL to MyModel.name 'parent': 'parent.name', # Map 'parent' to MyModel.parent.name }
The
InstanceLoader
mixin class will convert this mapping into SQLAlchemy attribute references to load the instance object.
-
-
coaster.views.classview.
route
(rule, **options)[source]¶ Decorator for defining routes on a
ClassView
and its methods. Accepts the same parameters that Flask’sapp.
route()
accepts. SeeClassView
for usage notes.
-
coaster.views.classview.
viewdata
(**kwargs)[source]¶ Decorator for adding additional data to a view method, to be used alongside
route()
. This data is accessible as thedata
attribute on the view handler.
-
coaster.views.classview.
url_change_check
(f)[source]¶ View method decorator that checks the URL of the loaded object in
self.obj
against the URL in the request (usingself.obj.url_for(__name__)
). If the URLs do not match, and the request is aGET
, it issues a redirect to the correct URL. Usage:@route('/doc/<document>') class MyModelView(UrlForView, InstanceLoader, ModelView): model = MyModel route_model_map = {'document': 'url_id_name'} @route('') @url_change_check @render_with(json=True) def view(self): return self.obj.current_access()
If the decorator is required for all view handlers in the class, use
UrlChangeCheck
.This decorator will only consider the URLs to be different if:
- Schemes differ (
http
vshttps
etc) - Hostnames differ (apart from a case difference, as user agents use lowercase)
- Paths differ
The current URL’s query will be copied to the redirect URL. The URL fragment (
#target_id
) is not available to the server and will be lost.- Schemes differ (
-
coaster.views.classview.
requires_roles
(roles)[source]¶ Decorator for
ModelView
views that limits access to the specified roles.
-
class
coaster.views.classview.
UrlChangeCheck
[source]¶ Mixin class for
ModelView
andUrlForMixin
that applies theurl_change_check()
decorator to all view handler methods. SubclassesUrlForView
, which it depends on to register the view with the model so that URLs can be generated. Usage:@route('/doc/<document>') class MyModelView(UrlChangeCheck, InstanceLoader, ModelView): model = MyModel route_model_map = {'document': 'url_id_name'} @route('') @render_with(json=True) def view(self): return self.obj.current_access()
-
class
coaster.views.classview.
UrlForView
[source]¶ Mixin class for
ModelView
that registers view handler methods withUrlForMixin
’sis_url_for()
.
-
class
coaster.views.classview.
InstanceLoader
[source]¶ Mixin class for
ModelView
that provides aloader()
that attempts to load an instance of the model based on attributes in theroute_model_map
dictionary.InstanceLoader
will traverse relationships (many-to-one or one-to-one) and perform a SQLJOIN
with the target class.