django-terms

Site-wide adds a definition or a link for specialized terms.

https://raw.github.com/BertrandBordage/django-terms/master/example_project/screenshot.png

Source:

https://github.com/BertrandBordage/django-terms

Code statistics:

https://www.openhub.net/p/django-terms/widgets/project_thin_badge.gif

PyPI status:

https://pypip.in/v/django-terms/badge.png https://pypip.in/d/django-terms/badge.png

Continuous integration status:

https://travis-ci.org/BertrandBordage/django-terms.png https://coveralls.io/repos/BertrandBordage/django-terms/badge.png

Live example

https://criminocorpus.org/musee/282/

(To learn more about the connection between django-terms and Criminocorpus, read the Bounty paragraph)

Table of contents

Contents:

Requirements

Mandatory

Optional

Installation

  1. [sudo] pip install django-terms
  2. Add 'terms', to your INSTALLED_APPS
  3. ./manage.py syncdb (./manage.py migrate terms if you use South)
  4. Add terms to your urls:
    • add url(r'^terms/', include('terms.urls')), to your urls.py
    • or, if you are using django-CMS, add a page and use the apphook and menu

Usage

  1. Add some terms in the admin
  2. Choose how django-terms should apply to your website:

The added terms should now be automatically linked to their definitions.

Middleware

A middleware is available to automatically add links on all your website. It is not recommended to use it in production because it parses and rebuilds whole pages, which can be an overkill in most cases (even though django-terms has excellent performances).

It is also perfect for development: it never fails silently, unlike filters (see Exceptions for more details).

  1. Add 'terms.middleware.TermsMiddleware', to your MIDDLEWARE_CLASSES
  2. If the middleware applies to unwanted Django applications, HTML tags, classes, or IDs, set the corresponding Common settings

Template filter

A template filter is available to add links only on desired parts of your website.

  1. Choose one of your existing templates
  2. Add {% load terms %} to the beginning of the file (just after {% extends '[file]' %} if you have one)
  3. Use the filter replace_terms like every normal filter
  4. If the filter applies to unwanted HTML tags, classes, or IDs, set the corresponding :ref:Common settings

Example:

Suppose you have such a template:

{% extends 'base.html' %}

{% block article_header %}
  {{ article.header }}
{% endblock %}

{% block article_content %}
  {{ article.section1 }}
  {{ article.section2 }}
{% endblock %}

Here is how you can modify it:

{% extends 'base.html' %}
{% load terms %}

{% block article_header %}
  {{ article.header|replace_terms }}
{% endblock %}

{% block article_content %}
  {% filter replace_terms %}
    {{ article.section1 }}
    {{ article.section2 }}
  {% endfilter %}
{% endblock %}

Now, suppose you have an HTML class code-snippet in article.section2 where you do not want to add links on terms. Go to Common settings, and you will find the solution:

Add this line in settings.py:

TERMS_ADDITIONAL_IGNORED_CLASSES = ['code-snippet']

With django-CMS

A few tools are available to make your life easier if you use django-CMS.

Plugin processor

It will automatically apply the Template filter on every plugin.

To use it, add or modify CMS_PLUGIN_PROCESSORS in settings.py:

CMS_PLUGIN_PROCESSORS = (
    ...
    'terms.cms_plugin_processors.TermsProcessor',
    ...
)
Glossary plugin

This plugin displays all terms and their definitions.

Don’t forget to update CMS_PLACEHOLDER_CONF in your settings.py if you defined it, otherwise this plugin will not be available from your placeholders.

Apart from this, nothing to do to make it work.

App hook and menu

You can use the the app hook and the menu to integrate the complete glossary to your CMS architecture.

Nothing to do to make it work.

Settings

Common settings

TERMS_ENABLED
Default:True
Definition:If set to False, globally disabled django-terms.
TERMS_DEBUG
Default:DEBUG
Definition:If set to True, allows django-terms to raise minor exceptions (see Exceptions).
TERMS_REPLACE_FIRST_ONLY
Default:True
Definition:If set to True, adds a link only on the first occurrence of each term
Used by:Middleware, Template filter
TERMS_ADDITIONAL_IGNORED_APPS
Default:()
Definition:A list or tuple of ignored Django applications (expressed as strings)
Used by:Middleware
Extends:TERMS_IGNORED_APPS
Syntax example:['cms']
TERMS_ADDITIONAL_IGNORED_TAGS
Default:()
Definition:A list or tuple of ignored HTML tags (expressed as strings)
Used by:Middleware, Template filter
Extends:TERMS_IGNORED_TAGS
Syntax example:['h1', 'h2', 'h3', 'footer']
TERMS_ADDITIONAL_IGNORED_CLASSES
Default:()
Definition:A list or tuple of ignored HTML classes (expressed as strings)
Used by:Middleware, Template filter
Extends:TERMS_IGNORED_CLASSES
Syntax example:['footnote', 'text-caption']
TERMS_ADDITIONAL_IGNORED_IDS
Default:()
Definition:A list or tuple of ignored HTML IDs (expressed as strings)
Used by:Middleware, Template filter
Extends:TERMS_IGNORED_IDS
Syntax example:['article-footer', 'side-content']
TERMS_DEFINITION_WIDGET
Default:'auto'
Definition:Explicitly tells django-terms which text widget to choose for the definition of a term. Accepted values are 'auto', 'basic', 'tinymce', and 'ckeditor'.

Advanced settings

These settings should not be used, unless you know perfectly what you are doing.

TERMS_IGNORED_APPS
Default:see terms/settings.py
Definition:A list or tuple of ignored Django applications (expressed as strings)
Used by:Middleware
TERMS_IGNORED_TAGS
Default:see terms/settings.py
Definition:A list or tuple of ignored HTML tags (expressed as strings)
Used by:Middleware, Template filter
TERMS_IGNORED_CLASSES
Default:see terms/settings.py
Definition:A list or tuple of ignored HTML classes (expressed as strings)
Used by:Middleware, Template filter
TERMS_IGNORED_IDS
Default:see terms/settings.py
Definition:A list or tuple of ignored HTML IDs (expressed as strings)
Used by:Middleware, Template filter

Troubleshooting

Side effects

Why?

When using django-terms, your HTML pages are totally or partially reconstructed:

The content is parsed and rebuilt with lxml. See terms/html.py to understand exactly how.

List of known side effects

A few side effects are therefore happening during HTML reconstruction:

  • Entity names and numbers (e.g. é, é, …) are unescaped. This means they are replaced with their unicode characters (e.g. é -> é)
  • Additional spaces inside HTML tags are stripped:
    • Start tags <a  href = "url" > -> <a href="url">
    • End tags </ a > -> </a>
    • “Start-end” tags <input  style = "text"  /> -> <input style="text"/>

Warning

This implies one bad side effect: the unescaping may break the special characters rendering in some complex form fields like django-ckeditor. django.contrib.admin is already ignored, so you should not encounter any problem. Otherwise, using filters instead of the middleware and/or ignore the correct apps/tags/classes/ids using Common settings will ensure a proper rendering.

Performance

Good news

django-terms nearly never hits the database. After each change in your terms table, the database is hit just one time in order to build a regular expression that’s saved into your cache (assuming you set up the cache). If you never change your terms and if your cache is never emptied, there will be zero database hit.

Considering memory, no particular leak has been found.

Bad news

Unfortunately, django-terms has a significant impact on speed, especially if you use the Middleware. That’s why we recommend using the Template filter.

What is important is the number of HTML tags wrapped by the filter or the middleware. Then comes the complexity of your HTML tree. The amount of flat text, luckily, has no impact.

To give you an idea, terms/tests/terms/performance_test_before.html contains 263 tags and takes 11 ms to be parsed and rebuilt on my computer with the middleware. That gives an average of 40 µs per tag. If you use the template tag only on the content of the page (124 tags), it takes 9 ms. Quite slow, but if you cache the part of the template that’s filtered, this issue should be negligible.

Exceptions

Resolver404
Raised by:Middleware only.
Raised in:TERMS_DEBUG mode. Otherwise the page is ignored by django-terms.
Reason:This happens when django-terms is unable to resolve the current request.path to determine whether the application of the current page is in TERMS_IGNORED_APPS.
Encountered:In django-CMS 2.3, when adding a plugin in frontend editing.

Translations

Status

https://www.transifex.com/projects/p/django-terms/resource/core/chart/image_png

Write your translation

Localization is done directly on our Transifex page. There is no access restriction, so feel free to spend two minutes translating django-terms to your language :o)

Get & Compile

  1. Make sure you have transifex-client installed: [sudo] pip install transifex-client
  2. Pull all translations from Transifex: tx pull -a
  3. Compile them: cd terms && django-admin.py compilemessages

Bounty & donations

Bounty

django-terms was originally developed for a french website, Criminocorpus. Now that it is finished, I don’t have credits to continue development on django-terms.

Maybe you want a new feature in django-terms but don’t want to code anything. First, open an issue on github so that we can publicly decide whether it’s a desirable feature. Then send me an email to privately discuss the cost of such a demand.

No donations…

I don’t accept donations for the time being.

Others would ask for donations in such cases, but in my opinion that would be quite dishonest because:

  • I’ve been paid to develop something that became django-terms, even though I was not supposed to make it open source, nor to make docs and tests.
  • I’m not a street mime, I can’t develop properly on the basis of a few bucks donated from time to time.
  • I don’t believe in Santa Claus.

If you’re still willing to help with money, see the next paragraph.

…but you can still help

The obvious help is to contribute to the code.

If you’re really willing to help but you can’t code, you can send me an email to say that you like django-terms, that’s always heartwarming :)

If you want to help me with money, please donate to PyPy (especially STM/AME). I’m not part of it, but that’s an awesome project that probably is the future of Python. It’s Python, but way faster. In a few years, maybe PyPy will become the main Python implementation, as was attempted with Unladen Swallow. Then django-terms will probably be much faster.

Getting help

If you have a question or need help, ask on our Google group.

If you spotted a bug or if you want to propose a new feature, open a new github issue.