Source code for thekraf.flaskapp.baseview

"""
thekraf.flaskapp.baseview
=========================

The base for all flaskapp views
"""
import flask
from flask.views import MethodView

from thekraf import __version__, Multilogr
import thekraf.config as cfg
from thekraf.flaskapp.nav import top_nav_elems

logr = Multilogr.get_logr('web')


[docs]class ViewBase(MethodView): """MethodView with contexts for backend template and frontend * Subclasses should subclass `TemplateContext` to add additional items to the context. * Update the frontend dict with ``ctx.update_frontend(d)``. This method is equivalent to ``dict.update()``. * ``ctx.frontend`` will become the json string, and this is done automatically by the base view. There is no reason to access this attr from a subclass. The frontend data is collected in a python dict. One of the final stages of rendering is to dump this dict as a string of json and save it to ``ctx.frontend``. Then, the base template creates a javascript script in which ``ctx`` is set to the json data. Then, the frontend can access this data via the ``ctx`` namespace. Attributes: ctx (ViewBase.TemplateContext): Context for project-specific data to be available from the backend template """
[docs] class TemplateContext(object): def __init__(self): self.version = __version__ self._frontend = { 'endpoint': flask.request.endpoint } self.frontend = None self.html = cfg.HTML self.top_nav_elems = top_nav_elems()
[docs] def prep_frontend(self): """Prepare frontend data by converting dict to json""" matches = cfg.load_config_item( 'tooltips', select=lambda x: x['endpoint'] == self._frontend['endpoint'] ) if matches: self._frontend['tooltips'] = matches[0] self.frontend = flask.json.htmlsafe_dumps(self._frontend, indent=2)
[docs] def update_frontend(self, other=None, **kwargs): """Update the frontend dict""" self._frontend.update(other=other, **kwargs)
@classmethod
[docs] def ctx_processor(cls): """Context processor for use with Flask-Security When customizing the Flask-Security views, this context processor must be added so the template context includes data available to all other views. Returns: dict: Dict of keyword args included with flask.render """ ctx = cls.TemplateContext() ctx.prep_frontend() d = { 'ctx': ctx, } return d
def __init__(self): super(ViewBase, self).__init__() self.ctx = self.TemplateContext()
[docs] def get(self): """Override with specific code for GET action Override should end by returning ``self.render()`` """ return self.render()
[docs] def post(self): """Override with specific code for POST action Override should end by returning ``self.render()`` or ``self.redirect_to_get()`` """ return self.render()
@classmethod
[docs] def redirect_to_get(cls, endpoint=None): """Redirect a POST action to the equivalent GET After a POST action, reloading the page results in the "Are you sure you want to send a form again?" dialog. One way to avoid this often annoying occurrence is to redirect to the equivalent GET. Notes: The POST data is lost upon redirect, so this only works if the POST data has been processed before the redirect. """ if endpoint is None: endpoint = flask.request.endpoint return flask.redirect(flask.url_for(endpoint), code=303)
[docs] def before_render(self): """This method runs before any other logic in the render method""" pass
[docs] def render(self): """Format data for the backend template and render the template""" self.before_render() # Create data to be available to the frontend self.ctx.prep_frontend() return flask.render_template( '{}.hamlish'.format(flask.request.endpoint), ctx=self.ctx)