= Migration of Templates to modules/templates = [[TOC]] == Introduction == We have changed the way templates are handled: * templates now live in modules/templates (formerly private/templates) * the template's config.py is now a Python module instead of a Python script and will be imported rather than executed * the settings in config.py have been moved into a function config() This has a couple of advantages: * being in the modules-path, templates can be imported and do not need to be re-compiled and executed on every request * templates are treated as Python packages so that config.py can import template-specific modules * config.py can now define classes and functions without risk for memory leaks * templates can share common modules via regular imports We have implemented a fallback logic for legacy templates, to give downstream projects some time to migrate. We highly recommend to migrate any legacy templates from private/templates to modules/templates. This page gives instructions how to do this. == Moving to modules/templates == Move the entire template folder to modules/templates. == Refactoring config.py == * Re-structure config.py so that all settings-assignment are inside a function config() (see example below, or check modules/templates/skeleton/config.py). * Do not assign any members of {{{current}}} to module-global variables (e.g. move "T = current.T" inside the config() function or wherever it is needed). * Function and class definitions can (should) still be at the module level, not inside the config() function. * Note that the variable "settings" is passed in as parameter for the config() function - so there is no need for "settings = current.deployment_settings". However, make sure that other functions in the template which depend on "settings" (or T) are fixed accordingly. * Remember that the config.py module is no longer executed for every request (only the config() function still is). Move therefore any module-global lookups (especially those related to the logged-in user!) into callbacks, so that functions which depend on them operate with updated data and data don't leak across threads/sessions. * The config() function returns nothing. Old config.py: {{{ # -*- coding: utf-8 -*- try: # Python 2.7 from collections import OrderedDict except: # Python 2.6 from gluon.contrib.simplejson.ordered_dict import OrderedDict from gluon import current from gluon.storage import Storage T = current.T settings = current.deployment_settings """ Template settings All settings which are to configure a specific template are located here Deployers should ideally not need to edit any other files outside of their template folder """ settings.base.system_name = "Example" settings.base.system_name_short = "Example" # PrePopulate data settings.base.prepopulate = ("default/users",) ... }}} New config.py: {{{ # -*- coding: utf-8 -*- try: # Python 2.7 from collections import OrderedDict except: # Python 2.6 from gluon.contrib.simplejson.ordered_dict import OrderedDict from gluon import current from gluon.storage import Storage def config(settings): """ Template settings All settings which are to configure a specific template are located here Deployers should ideally not need to edit any other files outside of their template folder """ T = current.T settings.base.system_name = "Example" settings.base.system_name_short = "Example" # PrePopulate data settings.base.prepopulate = ("default/users",) ... }}} == Adapt all Paths inside the Template == Some template files may still contain paths with "private/templates" (e.g. views/layout.html). Go through all the files and update these paths so that they find the template at the new location. == Changes in 000_config.py == In 000_config.py, you can replace this block: {{{ path = template_path() if os.path.exists(path): settings.exec_template(path) }}} with just this: {{{ settings.import_template() }}} The old statement will still work, but contains an unnecessary path check which should be avoided. The function template_path() is deprecated and will be removed over time. == Fallbacks == Most core functions have fallback paths for legacy templates and old-style config.py - but this support will be phased out over time. New core functionality will not support templates at the old location. It is therefore recommended to migrate all templates. Follow the steps above and/or ask for support on our mailing list to migrate your templates. == Importing Template Modules == If you have template-specific modules inside your template folder, you can import them in config.py like in any other Python package, e.g.: {{{ from controllers import index }}} Be careful with name collisions, though - ideally, module names like "gluon.py" or "s3.py" should be avoided inside templates. If there is an unresolvable name collision, make sure you are explicit about the import path for outside modules. To import shared modules from other templates, use the template-path, e.g.: {{{ from templates.SSF.controllers import subscriptions }}}