Trewq
Trewq

Reputation: 3237

sort in jinja2 when attribute is not available

I have a set of articles (using pelican for generating static sites) which includes a category called hotels. I'd like to sort these hotels. The problem is that only the hotels have an attribute called 'city' while the other articles do not and this obviously leads to the following error:

Caught exception "'pelican.contents.Article object' has no attribute 'city'".

Here is the code I am using:

{% for article in articles|sort(attribute='city') %}
{% if article.category == 'hotels' %}
    <a href="hotels/{{ article.slug }}.html">
    <p>{{ article.title }}</p>
    </a>
{% endif %}
{% endfor %}

Is there a way to check to see if the attribute exists and provide some default value so that it does not cause an error?

Upvotes: 1

Views: 2120

Answers (4)

endangered
endangered

Reputation: 83

If you want to show only entries that have a 'city' attribute, and have that list sorted by 'city', do:

for article in articles|selectattr("city")|sort(attribute="city")

Upvotes: 1

vorakl
vorakl

Reputation: 11

I found this page when was looking for a similar solution. Eventually, I solved it a bit differently and it might be helpful for someone else.

In one of my templates for Pelican I added statistics collected by 'post_stats' plugin about approximate time to read. It looked like

~{{ article.stats['read_mins']|default("0") }} min read

But if the plugin is not loaded then the 'article' object doesn't have the 'stats' attribute and rendering fails.

Jinja has the builtin test for testing if a variable is defined. So, I came up with this solution

~{{ article.stats['read_mins'] if article.stats is defined else "0" }} min read

Upvotes: 0

mgibsonbr
mgibsonbr

Reputation: 22007

If you want to iterate over only the hotels, see Sean Vieira's answer. If you want to iterate over all articles, but have the hotels sorted while the rest are in arbitrary order, you can do it by using macros:

{% macro my_macro(article) %}
    ...
{% endmacro %}

{% for a in articles if a.category == 'hotels' | sort(attribute='city') %}
    {{ my_macro(a) }}
{% endfor %}

{% for a in articles if a.category != 'hotels' %}
    {{ my_macro(a) }}
{% endfor %}

This will include everything you defined in my_macro first for each hotel, in the desired order, then for each article that is not a hotel.

Upvotes: 0

Sean Vieira
Sean Vieira

Reputation: 159905

You may be able to move your if statement into your for loop as a filter:

for article in articles if article.category == 'hotels' | sort(attribute='city')

Upvotes: 1

Related Questions