Question

To create custom django template tags and filters, as well as to add custom manage.py commands no matter how trivial, the docs tell you to create specific directory structures.

I'm working on a pretty tiny project, and it pains me to double the structural complexity of the application just to add a petite filter or command.

Is there any way of registering tags, filters and commands in a compact, straightforward manner? Imperatively wherever I want, rather than declaratively 2 levels down the directory hierarchy?

Était-ce utile?

La solution

Although a bit hackish, it turned out to be perfectly possible for the tag/filter case. Commands, no: django actually searches the filesystem for the .py files involved.

The template hack is completely self-contained -- it won't leak dubious stuff into nearby code. A single module can hold all of the metamagic, and be imported by regular modules.

First, we have to create a mock module. We'll create a nice decorator to turn regular classes into modules:

def module(path):
    def decorator(cls):
        if '.' in path:
            parent_path, name = path.rsplit('.', 1)
            module(parent_path)(type(name, (object,), { name: cls }))

        return sys.modules.setdefault(path, cls)
    return decorator

Yes, the recursion is necessary (we need the full import path mocked) and it can be used to create a fake templatetags module like this:

@module('app.templatetags.extras')
class TemplateExtras(object):
    class register:
        tags    = {}
        filters = {}

# Optional: avoid using {% load %}:
django.template.libraries['app.templatetags.extras'] = TemplateExtras
django.template.base.add_to_builtins('app.templatetags.extras')

Add two more pretty decorators into the mix...

def templatetag(f):
    return TemplateExtras.register.tags.setdefault(f.__name__, f)

def templatefilter(f):
    return TemplateExtras.register.filters.setdefault(f.__name__, f)

... and you get the following clean, straightforward syntax:

# imported or present in app/__init__.py
@templatefilter
def datestr(date):
    return datetime.strftime(date, '%Y-%m-%d')
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top