Part of my duties as a Hardware Certification Engineer is to develop and maintain our test and bug reports. Previously these have been Python scripts containing lots of inline HTML (yuck :/), which I’m ashamed to admit it because I didn’t know any better when I initially wrote them. 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.
So I have a list of systems which may be in different locations and I want to sort them by location. Initially I did this in the Python code which gathered the data, using a simple .sort(key = lambda obj: obj.datacentre)
. Then the template code used the sorted list and all was well. Later on when reading the Jinja template documentation I discovered a way to sort a list in the template itself. I considered this to be a cleaner, more transparent way to modify the list (somebody looking at the template asking ‘why does it come out in this order’ has the answer right in front of them). So I gave it a try by changing
for hw in {%reported_hardware %}
to
{% for hw in reported_hardware|sort(attribute='datacentre') %}
and was unfortunately confronted with a traceback from the template engine:
Traceback (most recent call last):
...
AttributeError: Hardware instance has no attribute '__getitem__'
This looks like it’s saying that the ‘Hardware’ object (which I’ll introduce in a second) isn’t the type that the template engine was expecting.
Initially I defined the Hardware object like this:
class Hardware:
def __init__(self..., datacentre):
...
self.datacentre = datacentre
My first attempt to fix this involved making datacentre a property:
@property
def datacentre(self):
return self._datacentre
But this didn’t seem to do the trick. Eventually I read in the Python documentation about the property built in working only on new-style classes and this set off the lightbulb
class Hardware(object):
This seemed to be the magic ingredient, and the sort in the template engine started working. I also realised that making datacentre a property wasn’t really necessary, so reverted that change.
Update: I found out that this whole problem is avoided by using Python3.x because all classes there are new-style classes. So the advice above only applies if you’re stuck with Python2.x