sort in jinja2 when attribute is not available

jinja2 sort
jinja2 filters
jinja dictionary
jinja2 tutorial
jinja2 set variable
jinja2 selectattr
jinja2 cheat sheet
jinja list comprehension

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?


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')

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'). The current workaround (using the fact that sorting is stable) looks extreme awful and is not intuitive: foo|sort(attribute='id')|sort(attribute='name') foo|sort(attribute=&amp;#39;name,id&amp;#39;) is quite useful in some cases.


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.

Thanks for the hint Sean.. I got this when I used your suggestion: CRITICAL: 'str object' has no attribute 'city'. Seems like the sort is applied to all objects in  I’m currently in the middle of refactoring (hopefully not ref**ktoring) the scripts to take advantage of a new API that’s available for querying data from the Certification website and have decided to use Jinja (precisely Jinja2) as the template engine.


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

There's no clean way to implement such modifiers since it's a generic function handling the attribute lookup from a string (remember, you can do  So recently, while solving an issue, I found this function in jinja2 to sort dictionaries. Its called the ‘d0_dictsort’ and is a function defined in jinja2.filters. Because we all know, python dicts are unsorted and many a times you may want to order them by either their key or value, this function comes handy:


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")

if there is not, check for an attribute called bar on foo . Note, however, that Python dicts are not ordered; so you might want to either pass a sorted list of tuple s  Load a template from the loader. If a loader is configured this method asks the loader for the template and returns a Template . If the parent parameter is not None, join_path () is called to get the real template name before loading. The globals parameter can be used to provide template wide globals.


Showing an undefined error for an object that raises AttributeError on access In for loops that access loop attributes, the iterator is not advanced Improved the sort filter (should have worked like this for a long time) by  Clears the cache. This method is not used by Jinja2 but should be implemented to allow applications to clear the bytecode cache used by a particular environment. class jinja2.bccache.Bucket(environment, key, checksum)¶ Buckets are used to store the bytecode for one template.


__next__() (jinja2.lexer.TokenStream method) · _fail_with_undefined_error() (​jinja2.Undefined method) · _undefined_exception (jinja2.Undefined attribute). Hi. I use Django 1.7.7 with Jinja2 2.7.3 via django-jinja 1.1.1. After update to django-jinja 1.3.1 got error: ./manage.py runserver Traceback (most recent call last): File "./manage.py", line 10, in <module> execute_from_command_line(sy


Hello, After some research it looks like Face is a derivative of python's Jinja templating system. This is great in the sense that there is actually some rather comprehensive sorted_values = presorted_values | sort(attribute="value") %} is that the documented Face filter "dictsort" does not seem to do anything particularly  Fixing Sort Problems. If it looks like the data did not sort properly, refer to the following list of possible solutions: Make sure no hidden rows or columns exist. Use a single row for headers. If you need a multiline header, either wrap the text in the cell or use Alt+Enter to force line breaks in the cell.