"TemplateSyntaxError: Invalid filter:"; custom django template filter based on django docs broken, but template tags working

codyc4321 picture codyc4321 · Aug 15, 2015 · Viewed 9.4k times · Source

I have a template filter based on the django docs at https://docs.djangoproject.com/en/1.8/howto/custom-template-tags/. For the life of me I can't see any difference in my usage and theirs, and am slowly going insane. I have a working tag I got on a forum as such:

myproject/index/templatetags/add_get_parameter.py:

from django.template import Library, Node, resolve_variable

register = Library()

class AddGetParameter(Node):
    def __init__(self, values):
        self.values = values

    def render(self, context):
        req = resolve_variable('request', context)
        params = req.GET.copy()
        for key, value in self.values.items():
            params[key] = value.resolve(context)
        return '?%s' %  params.urlencode()

@register.tag
def add_get(parser, token):
    pairs = token.split_contents()[1:]
    values = {}

    for pair in pairs:
        s = pair.split('=', 1)
        values[s[0]] = parser.compile_filter(s[1])
    return AddGetParameter(values)

This one, add_get on lines 8-9, works, whereas shorten_title on line 4 doesn't work:

myproject/templates/index/silo.html:

{% load bootstrap add_get_parameter extras %}



 ...other stuff...

{% for article in articles %}
        <div  class="col-md-4 article-link">
            <div class="panel panel-default hover">
                <div class="panel-heading"><h4 class="url-link">{{ article.title|shorten_title }}</h4></div>
                <div class="panel-body">
                    <p>&nbsp;<span class="url-text">{{ article.url }}</span></p>
                    <a href="{% url 'index:edit-article' article.id %}"><div class="article_button">Edit</div></a>
                    <a href="{% add_get archive=article.id %}"><div class="article_button"><p>Archive</p></div></a>
                    <a href="{% add_get delete=article.id %}"><div class="article_button">Delete</div></a>
                    <div style="margin-top:8px;">
                        {% for tag in article.tags.all %}
                            <p class="tag">{{ tag.name }}</p>
                        {% endfor %}
                    </div>
                </div>
              </div>
    </div>
{% endfor %}

Here's the villian:

from django.template import Library

register = Library()

@register.filter
def shorten_title(title):
    length = len(title)
    new = title
    if length > 65:
        new = title[0:65] + "..."
    return new
register.filter('shorten_title', shorten_title)

He's been so rude I double registered him, just to see what happens (he doesn't work registered once as a decorator or afterward, and doesn't work registered twice).

{{ article.title }} works, but {{ article.title|shorten_title }} breaks the page with:

django.template.base.TemplateSyntaxError
TemplateSyntaxError: Invalid filter: 'shorten_title'

'Index' is definitely registered and working, and the page works when I delete the filter from that article.title tag.

Usually when I get a stubborn error I missed something small, but following the docs word for word has me baffled (I've written several working filters before). Is this filter bad, or is there maybe something else in my page that causes the issue? Thanks

Answer

skyler picture skyler · Aug 15, 2015

You need to make sure you import the file with register.filter('shorten_title', shorten_title) before you render the template. Since that call happens outside of any functions it is run when you import the module. This has the side effect of registering it so that it will be available in your templates afterwards.