Ontospy

Python library and command-line interface for inspecting and visualizing RDF models aka ontologies.

View project on GitHub

Django to Jinja migration

As of version 2.0 (Oct 2022) Ontospy’s visualization module replaces Django with Jinja.

This is to make Ontospy footprint more lightweight, as well as to simplify future maintenance of the library. Django offers a lot of functionalities that are not needed by the simple use case of Ontospy: cranking out HTML pages from templates.

This page contains information of Django specific template filters, or constructs, that are not directly usable with Jinja and how they have been updated.

NOW

Django’s template tag now can be used in Jinja after installing the extension https://pypi.org/project/jinja2-time/.

Then you can do

{% now 'utc', '%a, %d %b %Y %H:%M:%S' %}

IFCHANGED

Django’s template tag ifchanged does not exist in Jinja. So a custom logic for caching iteration values via jinja assignments must be implemented. I found an example of this approach on https://groups.google.com/g/pocoo-libs/c/uRsxf9ivv2c

From

{% for each in o.annotations %}
    {% ifchanged each.1 %}
        {% if not forloop.first %}</dl>{% endif %}
            <dt>{{each.1}}</dt>
    {% endifchanged %}
    <dd>{{each.2|linebreaks}}</dd>
{% endfor %}

To

{% for each in o.annotations() %}
    {% if each.1 != variable_watcher  %}
        {% if not loop.first %}</dl>{% endif %}
            <dt>{{each.1}}</dt>
        {% set variable_watcher = each.1 %}
    {% else %}
    {% endif %}
    <dd>{{each.2|linebreaks}}</dd>
{% endfor %}

DEFAULT

Django’s template tag ifchanged has a slightly diffent syntax in Jinja.

From

{{s.qname|default:each.qname}}

To

{{s.qname|default(each.qname)}}

LINEBREAKS

Django’s template filter linebreaks does not exist in Jinja. It can be implemented as a custom filter (see this thread on SO)

import re
from markupsafe import Markup, escape
from jinja2 import pass_eval_context

_paragraph_re = re.compile(r'(?:\r\n|\r|\n){2,}')

@pass_eval_context
def linebreaks_filter(eval_ctx, value):
    result = u'\n\n'.join(u'<p>%s</p>' % p.replace('\n', '<br>\n')
                      for p in _paragraph_re.split(escape(value)))
    if eval_ctx.autoescape:
        result = Markup(result)
    return result

env.filters['linebreaks'] = linebreaks_filter

METHOD CALLS

Django’s templating language is ‘relaxed’ when it comes to resolving an object attribute or method call. In both cases, it’s enough to pass the attribute or method name.

With Jinja, method calls need to be followed by parentheses, like in Python. See also https://stackoverflow.com/questions/59589889/difference-between-an-item-and-an-attribute-jinja-python

From

{% for each in o.annotations %}

To

{% for each in o.annotations() %}

PS this applies to each.children() , each.parents(), each.rdf_source() etc..

IFEQUAL

From

{% ifequal objtype "class" #}"""

To

{% if objtype == "class" #}"""

WITH

From

{% with main_entity as each  #}"""
...
{% ifequal objtype "class" #}"""

To

{% if objtype == "class" #}"""

WITH

From

{% with main_entity as each  #}"""
...
{% endwith %}

To

{% set each = main_entity  #}"""
# no need to close anything

COMMENTS

See https://jinja.palletsprojects.com/en/3.1.x/templates/#comments

From

{% set each = main_entity  #}"""
# no need to close anything

COMMENTS

See https://jinja.palletsprojects.com/en/3.1.x/templates/#comments

From

{% comment %}

To

{% 
comment
#}"""