Search code examples
pythontemplatesflaskjinja2peewee

How to use pipe in Flask/Jinja template differently than filters?


I'm using Flask with the Jinja2 templating engine to build a website. As an ORM I use the (excellent) Peewee ORM and I now run into a problem.

In my Flask view I get a list of users from the DB:

@app.route('/stats')
def stats():
    users = User.select()
    return render_template('stats.html', users=users)

and in my template I loop over the users and try to expand the query. This works:

{% for user in users %}
    {{ user.app_logs.where(AppLog.type == 'LOGIN').first().created }}
{% endfor %}

but this:

{% for user in users %}
    {{ user.app_logs.where((AppLog.type == 'LOGIN') | (AppLog.type == AppLog.TICKET)).first().created }}
{% endfor %}

gives a TemplateSyntaxError: expected token 'name', got '('. I understand what the error comes from: the pipe symbol (|) is defined as a filter in Jinja. So I tried escaping it with a backslash (\|) but that doesn't work.

So my question: is there a way to somehow escape the pipe symbol or does anybody have any other idea to make this work? All tips are welcome!


Solution

  • In any case, it's a better practice to keep the template 'dumb' and to conduct your queries outside of the template. In your case you can use the playhouse extension to use hybrid attributes on the model.

    class User(Model):
        ...
    
        @hybrid_property
        def applog_login_ticket(self):
            return self.app_logs.where((AppLog.type == 'LOGIN') | (AppLog.type == AppLog.TICKET)).first().created()
    

    And then in your template you can just do

    {% for user in users %}
        {{ user.applog_login_ticket }}
    {% endfor %}