2 votes

Jinja2 check if a value exists in a dictionary list

I am trying to check if a value exists within a list with dictionary. I am using flask 1.0.2. See the example below:

person_list_dict = [
    {
        "name": "John Doe",
        "email": "johndoe@mydomain.com",
        "rol": "admin"
    },
    {
        "name": "John Smith",
        "email": "johnsmith@mydomain.com",
        "rol": "user"
    }
]

I found two ways to solve the problem, can you tell me which one is better?

First option: jinja2 built-in template filter "map".

<pre>{% if "admin" in person_list_dict|map(attribute="rol") %}SI{% else %}NO{% endif %}</pre>
# return SI (john doe) and NO (john smith)

Second option: Flask template filter

Flash code:

@app.template_filter("is_in_list_dict")
def is_any(search="", list_dict=None, dict_key=""):
    if any(search in element[dict_key] for element in list_dict):
        return True
    return False

template code:

<pre>{% if "admin"|is_in_list_dict(person_list_dict, "rol") %} SI {% else %} NO {% endif %}</pre>
# return SI (john doe) and NO (john smith)

Thank you :-).

1voto

abulafia Points 18959

Although it could be considered a matter of opinion, I believe there are objective reasons to prefer the first approach. They would be the following:

  1. Less code . Since you are using pre-existing jinja2 filters, you don't need to add extra code in your Flask application. Less things to maintain and test.

  2. More readable code . Although the part of map(attribute="rol") requires knowing what exactly this function does in jinja2, it is not difficult to imagine what it will be. Once it is understood that all the "role" fields have been extracted from the dictionary list, it is obvious that it is enough to search if the string "admin" is among them. On the other hand, the Flask version requires an understanding of what a decorator is. template_filter understand that the list comprehension that appears in the function produces a list of booleans, and knowing the function any() . Furthermore, once this filter is created in Flask, its use within the template is also counter-intuitive, since it is not really being used to filter a list (i.e., select items from it), but rather as a condition for the if.

  3. Efficiency . Not yet known how Jinja2 actually implements the filter. map we can assume that in the background he will be making a list comprehension which will result in the list of strings found in the "role" field. The time required to create this list will be proportional to the number of elements in the list. Once you have it, the operator cadena in lista will be translated to the same operator in in Python, which is very efficient. The second version also needs to traverse the entire dictionary list, to create a list of booleans, and then any() need to check if there are any True (which is also very efficient, as it does not go through the entire list and stops at the first True I find). Even so, the second version requires more operations when creating the boolean list, since for each element of the original list it must compare its "role" with the searched one, and it does that for all the elements of the list (when it could have stopped when finding the first one).

    It may seem that the difference would be negligible, but I have made some measurements and, for a list with only two elements, the first option takes 631ns and the second 833ns. Nanosecond differences are obviously irrelevant, but if the list were much longer they could already be important, since the second option takes about 25% longer than the first one.

    Not only is the processing time of the second option slightly longer, but it also adds an extra level of indirection in its execution, as the renderer of the Jinja template must invoke the python function that acts as a filter. However the invocation is performed only once and the time consumed here does not depend on the size of the list.

  4. Robustness . If you try to look at a field that does not exist in the dictionaries (e.g., you change "rol" by "role" the first option will continue to work, and will result in <pre>NO</pre> which is reasonable. The second option will produce an exception in the python function when trying to access element[dict_key] .

0 votes

It was more or less what I thought and your answer convinced me. Thank you @abulafia

HolaDevs.com

HolaDevs is an online community of programmers and software lovers.
You can check other people responses or create a new question if you don't find a solution

Powered by:

X