Hadi Farah
Hadi Farah

Reputation: 1162

jinja2 groupby grouping a custom sorted list of dictionaries

I have the following issue with groupby function in jinja:

I have a list of Dicts, where one key inside each is [Tech]:**some tech value**

and I want to sort and group in a custom manner, let's say I have

tech_order = [tech2, tech5, tech1, tech3, tech4] #these values are arbitrary just for example

When I do this using python only

def custom_sort_list_dictated(Dict, Key, list_order):
    Dict = Dict.sort(key=lambda k:list_order.index(k[Key])) 
#Written as function because I pass it later in jinja2.Environment.globals.update()

custom_sort_list_dictated(My_list_of_dicts, 'Tech', tech_order) 
#This works and sorts my dictionaries correctly

for key, value in itertools.groupby(Anforderungen, key=itemgetter('Tech')):
            Val_list.append(list(value))    # Store group iterator as a list
            Key_list.append(key)

Using itertools.groupby in python will group my custom sorted dictionaries according to my tech_order list and group them conserving the order.

This however is not the case in jinja2, I have the following template:

{{ custom_sort_list_dictated(My_list_of_dicts, 'Tech', tech_order) or '' }}

{% for Tech, group_by_tech in My_list_of_dicts|groupby('Tech') %}
        {{ jinja_append_array(Val_Array, list(group_by_tech)) or '' }}
        {{ jinja_append_array(Key_Array, Tech) or '' }}
{% endfor %}

However groupby in jinja2 sorts my dictionaries back in alphabetical order, unlike itertools.groupby in python. Is there a way not to have this happen?

I know the issue is jinja2 groupby because just calling:

{% for Tech, group_by_tech in My_list_of_dicts|groupby('Tech') %}
        {{ Tech + " ~~ " }}
{% endfor %} #This prints my techs in alphabetical order which is not consistent with itertools.groupby 

PS: jinja_append_array and custom_sort_list_dictated are passed from python to jinja using jinja2.Environment.globals.update()

Upvotes: 0

Views: 2142

Answers (1)

Hadi Farah
Hadi Farah

Reputation: 1162

Ended up making my own groupby() custom function and passing it into inja2.Environment.globals.update() as follows:

import jinja2
import itertools
from operator import itemgetter


def custom_jinja_groupby(Dict, Key_list, Val_list, group_filter, parse_filter):
    temp_array = []
    for key, value in itertools.groupby(Dict, key=itemgetter(group_filter)):
        Key_list.append(key)
        for content in value:
            Parse_Info_Dictionary(content, parse_filter) #another custom function as I needed to make some changes to my grouping
            temp_array.append(content)
        Val_list.append(temp_array)
        temp_array=[]

template_file_loader = jinja2.FileSystemLoader('{}'.format(path_to_jinja_template_folder))
env = jinja2.Environment(loader = template_file_loader)
env.globals.update(custom_jinja_groupby = custom_jinja_groupby)

I can use this in my Jinja file as follows:

{{ custom_jinja_groupby(My_Dict_To_Group, Key_Array, Val_Array, 'group_by_This', 'Custom_function_at_This') or '' }}

Note the or '' is used because otherwise it will print None into your rendered file, this will have it print nothing and still perform the function changes. The goal is getting Key_Array and 'Val_Array' which are passed by reference I guesss inside the jinja file but this will pretty much keep your custom ordering after grouping. Hope this helps someone later on.

Upvotes: 1

Related Questions