Welcome | Get started | Dive | Contribute | Topics | Reference | Changes | More
jinja : Use the Jinja template engine¶
This document describes the lino.modlib.jinja plugin.
This page contains code snippets (lines starting with >>>), which are
being tested during our development workflow. The following
snippet initializes the demo project used throughout this page.
>>> from lino import startup
>>> startup('lino_book.projects.min1.settings')
>>> from lino.api.doctest import *
>>> from atelier.sheller import Sheller
>>> shell = Sheller("lino_book/projects/min1")
Plugin settings¶
Two settings to be used by the local.css file.
- lino.modlib.jinja.tile_width¶
The width of each tile for tables in display mode “tiles”.
Default value is
"20em".
- lino.modlib.jinja.background_color¶
The background color of tiles for tables in display mode “tiles” and certain other elements. Default value is
"Gainsboro".
The local.css file¶
This file contains CSS available in all front ends.
Build methods¶
This module adds a build method for lino.modlib.printing.
- class lino.modlib.jinja.JinjaBuildMethod¶
Inherits from
lino.modlib.printing.DjangoBuildMethod.
Model mixins¶
- class lino.modlib.jinja.XMLMaker¶
Usage example in Lino and XML
- xml_file_name¶
The name of the XML file to generate. This file will be overwritten without asking. The name formatted with one name
selfin the context.
- xml_file_template¶
The name of a Jinja template to render for generating the XML content.
This must be either None or a
Pathobject.
- xml_validator_file¶
The name of a “validator” to use for validating the XML content.
This must be either None or a
Pathobject.Lino choose the validation method from the file’s suffix. It currently can handle suffixes “.xsd” and “.sch”.
- get_xml_file()¶
Get the name of the XML file to be generated for this database row.
Returns an instance of
lino.utils.media.MediaFile.
- make_xml_file(ar)¶
Make the XML file for this database row.
Table classes¶
- class lino.modlib.jinja.TableClasses¶
A choicelist of supported class names for tables in a rich text field.
For #6907 (Add a TableClasses choicelist and use it in Quill’s table properties dialog):
>>> rt.show(jinja.TableClasses)
======= =========== =========== ====================================
value name text CSS code
------- ----------- ----------- ------------------------------------
010 default Default
020 frameless Frameless .l-table-frameless td { border:0;}
======= =========== =========== ====================================
django-admin commands¶
This plugin defines the following django-admin commands:
pm hello,
pm showsettings and
pm status.
- pm hello¶
>>> shell("python manage.py hello --help")
...
usage: manage.py hello [-h] [-b] [-s RECIPIENT] [--version] [-v {0,1,2,3}] [--settings SETTINGS] [--pythonpath PYTHONPATH] [--traceback] [--no-color] [--force-color]
[--skip-checks]
Send an email with information about this Lino site to the server administrator(s).
options:
-h, --help show this help message and exit
-b, --batch, --noinput
Do not prompt for input of any kind.
-s..., --sendto RECIPIENT
Send email to recipient instead of site ADMINS.
--version Show program's version number and exit.
-v..., --verbosity {0,1,2,3}
Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output
--settings SETTINGS The Python path to a settings module, e.g. "myproject.settings.main". If this isn't provided, the DJANGO_SETTINGS_MODULE environment variable
will be used.
--pythonpath PYTHONPATH
A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".
--traceback Display a full stack trace on CommandError exceptions.
--no-color Don't colorize the command output.
--force-color Force colorization of the command output.
--skip-checks Skip system checks.
- pm showsettings¶
>>> shell("python manage.py showsettings --help")
...
usage: manage.py showsettings [-h] [-a] [--version] [-v {0,1,2,3}] [--settings SETTINGS] [--pythonpath PYTHONPATH] [--traceback] [--no-color] [--force-color] [--skip-checks]
Print the settings of this Lino site to the console.
options:
-h, --help show this help message and exit
-a, --all Also show undocumented settings.
--version Show program's version number and exit.
-v..., --verbosity {0,1,2,3}
Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output
--settings SETTINGS The Python path to a settings module, e.g. "myproject.settings.main". If this isn't provided, the DJANGO_SETTINGS_MODULE environment variable will be used.
--pythonpath PYTHONPATH
A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".
--traceback Display a full stack trace on CommandError exceptions.
--no-color Don't colorize the command output.
--force-color Force colorization of the command output.
--skip-checks Skip system checks.
Usage example:
>>> shell("python manage.py showsettings")
...
jinja.background_color = 'Gainsboro' # The background color of tiles for tables in display mode “tiles” and certain other elements. Default value is "Gainsboro".
jinja.tile_width = '20em' # The width of each tile for tables in display mode “tiles”.
extjs.autorefresh_seconds = 0 # Number of seconds to wait between two refreshes of the dashboard. Default is 0, which deactivates the feature.
extjs.enter_submits_form = False # Whether the ENTER key (or CTRL+ENTER when in a textarea field) should submit the form.
extjs.use_statusbar = False # Whether to use a status bar to display certain messages to the user. Default is False since currently this is not really useful.
system.host2config = {} # A dictionary that maps the return value of HttpRequest.get_host() to the primary key of the SiteConfig instance to use.
system.site_config_id = 1 # The primary key of the SiteConfig instance to use by default on this site.
system.with_mptt = False # Whether Hierarchical should use django-mptt to optimize database access when navigating in hierarchical trees. See mptt_in_hierarchical.
users.demo_username = 'robin' # The username of the default site user.
users.private_default = True # Default value for the PrivacyRelevant.private field.
users.with_phone = False # Whether we want to store the phone number of a user account in its User.phone field.
contacts.demo_region = None # Which distribution of demo names to use. Available dists are BE and EE and UY.
contacts.privacy_relevant = False # Whether partners should be PrivacyRelevant
contacts.region_label = 'Region' # The verbose name of the Partner.region field.
contacts.show_birthdays = True # Whether to show upcoming and recent birthdays as a welcome message in the dashboard.
contacts.site_owner = Company #1 ('Rumma & Ko OÜ') # A property holding the database row representing the site owner.
contacts.site_owner_id = 1 # The id (primary key) of the business partner who represents the site owner.
contacts.site_owner_lookup = {'id': 1} # An optional dictionary to be used for looking up the site owner.
contacts.use_vcard_export = False # Whether Lino should provide a button for exporting contact data as a vcf file.
contacts.with_partner_ref = False # Whether to use the field Partner.partner_ref.
contacts.with_roles_history = False # Whether we maintain a history of contact persons.
The pm showsettings command no longer has an alternative form that also
prints the Django settings. You can do that using the build-in Django commend
diffsettings
instead. The following example then greps the output to show only those
containing “EMAIL”.
>>> shell("python manage.py diffsettings --all | grep EMAIL")
...
### DEFAULT_FROM_EMAIL = 'webmaster@localhost'
### EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'mail.example.com'
### EMAIL_HOST_PASSWORD = ''
### EMAIL_HOST_USER = ''
### EMAIL_PORT = 25
### EMAIL_SSL_CERTFILE = None
### EMAIL_SSL_KEYFILE = None
EMAIL_SUBJECT_PREFIX = '[min1] '
### EMAIL_TIMEOUT = None
### EMAIL_USE_LOCALTIME = False
### EMAIL_USE_SSL = False
### EMAIL_USE_TLS = False
### SERVER_EMAIL = 'root@localhost'
- pm status¶
>>> shell = Sheller("lino_book/projects/min1")
>>> shell("python manage.py status")
...
Plugins
=======
- lino : lino
- about : lino.modlib.about
- jinja : lino.modlib.jinja
- extjs : lino.modlib.extjs
- system : lino.modlib.system
- users : lino.modlib.users
- office : lino.modlib.office
- xl : lino_xl.lib.xl
- countries : lino_xl.lib.countries
- contacts : lino_xl.lib.contacts
- staticfiles : django.contrib.staticfiles
- sessions : django.contrib.sessions
Config directories
==================
- .../lino_xl/lib/contacts/config
- .../lino/modlib/users/config
- .../lino/modlib/extjs/config
- .../lino/modlib/jinja/config
- .../lino/config
Mail settings
=============
- ADMINS: []
- DEFAULT_FROM_EMAIL: webmaster@localhost
- EMAIL_BACKEND: django.core.mail.backends.smtp.EmailBackend
- EMAIL_HOST: mail.example.com
- EMAIL_HOST_PASSWORD:
- EMAIL_HOST_USER:
- EMAIL_PORT: 25
- EMAIL_SSL_CERTFILE: None
- EMAIL_SSL_KEYFILE: None
- EMAIL_SUBJECT_PREFIX: [min1]
- EMAIL_TIMEOUT: None
- EMAIL_USE_LOCALTIME: False
- EMAIL_USE_SSL: False
- EMAIL_USE_TLS: False
- SERVER_EMAIL: root@localhost
Memo commands
=============
(The memo plugin is not installed)
- -s¶
>>> shell("python manage.py status --help")
...
usage: manage.py status [-h] [-b] [-s RECIPIENT] [--version] [-v {0,1,2,3}]
[--settings SETTINGS] [--pythonpath PYTHONPATH] [--traceback]
[--no-color] [--force-color] [--skip-checks]
Print a configuration summary for this Lino site to the console, or send it via email.
options:
-h, --help show this help message and exit
-b, --batch, --noinput
Do not prompt for input of any kind.
-s... --sendto RECIPIENT
Also send the report as email to recipient.
--version Show program's version number and exit.
-v... --verbosity {0,1,2,3}
Verbosity level; 0=minimal output, 1=normal output,
2=verbose output, 3=very verbose output
--settings SETTINGS The Python path to a settings module, e.g. "myproject.settings.main".
If this isn't provided, the DJANGO_SETTINGS_MODULE
environment variable will be used.
--pythonpath PYTHONPATH
A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".
--traceback Display a full stack trace on CommandError exceptions.
--no-color Don't colorize the command output.
--force-color Force colorization of the command output.
--skip-checks Skip system checks.
The output may be
customized by overriding the jinja/status.jinja.rst template.
The pm status command is a functional replacement for the diag
command.
- jinja/status.jinja.rst¶
The template file used by the status command.
The Jinja template context¶
The context returned by ar.get_printable_context contains a series of
names that a server administrator can use in local templates. These
names are simple shortcuts to their respective functions imported from
well-known places:
Count, Sum, Max, Min, Avg, F are those from
django.db.models; see https://docs.djangoproject.com/en/6.0/topics/db/aggregation/_refers todjango.utils.translation.gettext()aris the action requestactivate_languagerefers todjango.utils.translation.activate()requested_languagerefers todjango.utils.translation.get_language()and many more (see below and consult the source code)
Here is a snippet that show them all:
>>> ar = rt.login()
>>> sorted(ar.get_printable_context().keys())
['Avg', 'Count', 'Decimal', 'E', 'F', 'Max', 'Min', 'Sum', '_', 'activate_language', 'ar',
'bool2js', 'bool2text', 'dd', 'decfmt', 'fdf', 'fdl', 'fdm', 'fdmy', 'fds',
'getattr', 'iif', 'now', 'parse', 'pgettext', 'requested_language', 'restify',
'rt', 'tostring', 'unicode']
>>> pprint(ar.get_printable_context())
{'Avg': <class 'django.db.models.aggregates.Avg'>,
'Count': <class 'django.db.models.aggregates.Count'>,
'Decimal': <class 'decimal.Decimal'>,
'E': <lxml.builder.ElementMaker object at ...>,
'F': <class 'django.db.models.expressions.F'>,
'Max': <class 'django.db.models.aggregates.Max'>,
'Min': <class 'django.db.models.aggregates.Min'>,
'Sum': <class 'django.db.models.aggregates.Sum'>,
'_': <function gettext at ...>,
'activate_language': <function activate at ...>,
'ar': <lino.core.requests.BaseRequest object at ...>,
'bool2js': <function BaseRequest.get_printable_context.<locals>.<lambda> at ...>,
'bool2text': <function bool2text at ...>,
'dd': <module 'lino.api.dd' from '.../lino/api/dd.py'>,
'decfmt': <bound method Site.decfmt of <lino_book.projects.min1.settings.Site object at ...>>,
'fdf': <function fdf at ...>,
'fdl': <function fdl at ...>,
'fdm': <function fdm at ...>,
'fdmy': <function fdmy at ...>,
'fds': <function fds at ...>,
'getattr': <built-in function getattr>,
'iif': <function iif at ...>,
'now': datetime.datetime(2014, 10, 23, ...),
'parse': <function BaseRequest.get_printable_context.<locals>.parse at ...>,
'pgettext': <function pgettext at ...>,
'requested_language': 'en',
'restify': <function restify at ...>,
'rt': <module 'lino.api.rt' from '.../lino/api/rt.py'>,
'tostring': <function tostring at ...>,
'unicode': <class 'str'>}
The parse function¶
One of these names is parse(), which deserves some attention:
- lino.modlib.jinja.parse(s)¶
Parse the given string using the current template context.
Let’s illustrate this parse() function in a simplified context:
>>> ctx = dict(x=1, y=2, a="A")
>>> def test(s):
... print(dd.plugins.jinja.renderer.parse(s, **ctx))
>>> test("Hello, world")
Hello, world
>>> test("x is {{x}} and a is {{a}}")
x is 1 and a is A
But what if we want to insert a string that is configurable via a jinja template in the site settings? The following won’t do what we expect:
>>> ctx.update(footer_content="x is {{x}} and a is {{a}}")
>>> test("{{footer_content}}")
x is {{x}} and a is {{a}}
That’s why the template context also contains a parse() function. The
following simulates what Lino does, for illustration:
>>> def parse(s):
... return dd.plugins.jinja.renderer.parse(s, **ctx)
>>> ctx.update(parse=parse)
>>> test("{{parse(footer_content)}}")
x is 1 and a is A
Edge cases¶
Parsing an empty string returns an empty string:
>>> test('')
The following exception was added for #6643 (When Jinja says “Can’t compile non template nodes”):
>>> test(1)
Traceback (most recent call last):
...
Exception: 1 is not a string (context is {...})
>>> s = 1
>>> dd.plugins.jinja.renderer.jinja_env.from_string(s).render(**ctx)
Traceback (most recent call last):
...
TypeError: Can't compile non template nodes