Variable Access Implementation Details
n
Understanding the underlying mechanics of how Jinja resolves variables and attributes is crucial for avoiding unexpected behavior in your templates. While foo.bar and foo['bar'] may seem interchangeable, but there are subtle but important differences in their lookup sequence. This behavior is key if an object has both an attribute and an item with the same name.
nn
The Lookup Sequence
n
For the sake of convenience, Jinja performs a specific lookup sequence on the underlying Python object to resolve a variable. Here is how it works for each type of syntax:
nn
Dot Notation: `foo.bar`
n
- n
- Step 1: Jinja first checks for an attribute called
baron thefooobject. This is equivalent to callinggetattr(foo, 'bar')in Python. - Step 2: If no attribute is found, it then checks for an item
'bar'infoo. This is equivalent to callingfoo['bar']. - Step 3: If neither an attribute nor an item is found, it returns an undefined object.
n
n
n
n
Subscript Syntax: `foo[‘bar’]`
n
- n
- Step 1: Jinja first checks for an item
'bar'in thefooobject. - Step 2: If no item is found, it then checks for an attribute called
baron `foo`. - Step 3: If neither an item nor an attribute is found, it returns an undefined object.
n
n
n
n
nn
Key Difference and the attr() Filter
n
The difference in the lookup sequence is crucial. If an object has both an attribute and an item with the same name, the result will vary depending on the syntax you use. The dot notation will return the attribute, while the subscript syntax will return the item. This behavior allows you to be explicit about which value you want to retrieve. Additionally, Jinja’s built-in attr() filter is designed to exclusively look up attributes, providing another tool for precise variable access.
nn
{# Given a variable my_data that is both a dict and has an attribute name #} {{ my_data.name }} {# This will return the attribute #} {{ my_data['name'] }} {# This will return the item from the dictionary #}
n
n
