mitsuhiko/flask — Issue #424: Allow entire blueprints to have lazy-loaded views despite using route decorators
Author: jamesonquinn
Created: 2012-03-08 22:00:26+00:00
State: open

For me, a single blueprint naturally goes in a module folder, and all the views go in a views.py there. If that's how you do it, it makes sense to lazy-load one blueprint at a time. But in order to do that, you have to change your whole routing system, using add_url_rule() instead of @bp.route(). I've got a fix for this, but it takes some modification of flask itself (so that there's a way to later .remove() the temporary lazy-loader rule added by add_url_rule; and so that you can app.full_redispatch_request after the lazy-loading is done).

Is this some horrid sin from the evil world of Django, or would my patches be welcome, or what?

Here's my lazyblueprint.py for reference:

from flask import Blueprint

class LazyBlueprint(Blueprint):
def __init__(self, name, import_name, static_folder=None,
static_url_path=None, template_folder=None,
url_prefix=None, subdomain=None, url_defaults=None):
super(LazyBlueprint, self).__init__(name, import_name, static_folder,
static_url_path, template_folder,
url_prefix, subdomain, url_defaults)
self.views = '.'.join([import_name,'views'])
print import_name, self.views
self.lazyrules = []
self.states = []
self.record(self.setuplazyload)

def setuplazyload(self, state):
self.lazyrules.append(state.add_url_rule('/', 'index', self.lazyloadfor(state)))
self.lazyrules.append(state.add_url_rule('/', 'index', self.lazyloadfor(state),
defaults={'endpoint':''}))
self.states.append(state)

def lazyloadfor(self, state):
def innerlazyload(endpoint, **kw):
for rule in self.lazyrules:
rule.remove()
self.base_functions, self.deferred_functions = self.deferred_functions, []
__import__(self.views)

state.app.debug, debug = False, state.app.debug #don't trigger setupfunction warnings
for fixstate in self.states:
for deferred in self.deferred_functions:
deferred(fixstate)
state.app.debug = debug
self.deferred_functions = self.base_functions + self.deferred_functions
return self.redispatch(state, endpoint, **kw)
return innerlazyload

def redispatch(self, state, endpoint, **kw):
return state.app.full_redispatch_request()

Here's how you'd use it: first skyblue/__init__.py:

from lazyblueprint import LazyBlueprint

skyblue = LazyBlueprint('simple_page', __name__,
template_folder='templates')

then skyblue/views.py:

from skyblue import skyblue

@skyblue.route('/')
def index():
return "

sky:1...blue:2...Say hi!

"

@skyblue.route('/hello')
def hello():
return "Hello skyblue!"