📜 ⬆️ ⬇️

Django do-it-yourself part 1: Putting templates for jinja2

Introduction


In this post I would like to describe the creation of a small framework with a system of plug-ins as django. Only using external components. Jinja2 for templates, bottle for getting environment variables, pymongo will be used instead of ORM, and beaker will deal with sessions.
In the first part I want to tell you how convenient it is to connect Jinja2 so that templates can be collected from different folders (read plug-ins) and cache them.
Also in the next part I would like to tell you how to connect to gettext templates and automate their translation.

Framework structure


It is assumed that our framework as a library may be located in any directory most likely for ubuntu '/usr/local/lib/python2.6/dist-packages/', and the project is not where, say, for example, '/ home / user / worckspace / '. The project has index.wsgi for mod_wsgi or for uwsgi index_wsgi.py which contains the path to our library, if it was manually copied somewhere.
The project has approximately the following structure:
/project/ /__init__.py /app/ /__init__.py /app1/ /__init__.py /templ/ /static/ /routes.py /models.py /views.py /teml/ /static/ /index.py /routes.py /views.py /models.py /settings.py 

Accordingly, in the / templ subdirectories there will be templates, in / static statics, in / app any number of applications (or components, as you like).
Accordingly, it is assumed that in our library there is also an app folder, an analogue of the jung contrib which will also contain components with their own templates.
Also in the project for silence, a folder will be created, for example, a caine in it jinja2 will save the template cache.

Connecting patterns


So all our connection will be in the core.py file in the core package, which in turn lies in the root of the library. Import the necessary classes.
 from jinja2 import Environment, PackageLoader, FunctionLoader, FileSystemBytecodeCache 

Next, we define the path for the templates; we will call this function when loading templates.
Templates to choose from may have several extensions.
 def get_app_root(app): """Returns path to app or app name.""" if isinstance(app, (str, )): __import__(app) app = sys.modules[app] return os.path.dirname(os.path.abspath(app.__file__)) templ_exts = ['', '.tpl', '.html', '.htm'] def split_templ_name (t): """     .            .       . """ if ':' in t: #        module, file = t.split(":", 1) module_path = os.path.join(get_app_root( module), "templ", "") else: #        . module = ' ' module_path = os.sep + 'templ' + os.sep file = t return (module, module_path, file) 

Actually loading templates.
Here you can implement alternative storage locations for templates, for example, by implementing a load from the database
 def union_templ(t, **p): (module, module_path, file) = split_templ_name (t) def load_template (base, module_path, file): path = base + module_path + file template = ' ' for ext in templ_exts: filename = path+ext if os.path.exists(filename): with open(filename, "rb") as f: template = f.read() break; return template template = load_template (os.getcwd(), module_path, file); if not template: template = load_template( settings.lib_path, module_path, file); if not template: return 'Template not found %s' % t return template.decode('UTF-8') 

')
Automatic creation of a folder for caching templates.
 jcp = os.path.join(os.getcwd(), 'jinja_cache') if not os.path.isdir(jcp): os.mkdir(jcp) 


Creating an object that manages the cache.
 bcc = FileSystemBytecodeCache(jcp, '%s.cache') 


Hang the hook on jinja2, where we point out the need for caching and pass the function that needs to be called to load the templates.

 jinja = Environment(auto_reload=True, loader=FunctionLoader(union_templ), bytecode_cache = bcc ) 


A function that directly performs template rendering. Now she does not do anything special, directly transferring control to jinja2, but we'll come back here.
 def render_templ(t, **p): template = jinja.get_template(t) return template.render(**p) 


Import this feature to the global level.
 __builtin__.templ = render_templ 


Now, thanks to this last line, it will be sufficient in any file to call the templ () function and pass the template name to it in the arguments and what to output in it. For example:
return templ ('app.base: base', param = param) or return templ ('base', param = param), ':' means that the template is not in the project, but in the corresponding component in this case 'app.base '.

Summary


So for starters, we have a small framework with a modular structure. On the basis of which we will move on.
This is still the first article and much, probably, could be written better, so I will be glad to all the comments and questions.

Continuation

Source: https://habr.com/ru/post/144717/


All Articles