I have used Jinja in all of my projects that use Flask. It’s a simple way to get Python syntax into a HTML page.
Details about the project and full documentation can be found here.
I will show how I have used Jinja in my Multicast Daskboard, part of my Scrapli and Flask Project.
I have passed into the HTML page two variables. One is a list of dictionaries (parsed_output) and the second a dictionary (show_output_dict).
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
@devices_blueprint.route('/bg_get_mroute', methods = ['GET', 'POST']) def bg_get_mroute(): """ Gets the multicast routing table and parses it """ # Get form values form_IPs = session.get("form_IPs", None) ips = form_IPs['mcast_routers'][0]['ip'].replace(" ", "").replace("\r\n\r\n", "").replace("\r\n", "").split(',') # ips = ["172.16.1.115","172.16.1.116","172.16.1.117","172.16.1.118"] # Perform show ip mroute get_detailed = CiscoCommands() genie_list, error_ips = get_detailed.create_threads(ips, "show_mroute") show_output_dict = {} parsed_output = [] for device in genie_list: for key, value in device.items(): if key != "show_output": show_output_dict.update({key:re.split('\n\n|\n|\n\n\n',device['show_output'])}) parsed_output.append({key:value}) return render_template('bg_get_mroute.html', show_output_dict=show_output_dict, parsed_output=parsed_output) |
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
{% extends "base.html" %} {% block content %} <div class="jumbotron"> <h1>Multicast Details</h1> </div> <br> <br> <div class="container"> <div class="jumbotron"> <ul class="nav nav-tabs"> <li class="nav-item"> <a class="nav-link active" data-toggle="tab" href="#quickstats">Multicast Basics</a> </li> <li class="nav-item"> <a class="nav-link" data-toggle="tab" href="#portdetail">Multicast Details</a> </li> <li class="nav-item"> <a class="nav-link" data-toggle="tab" href="#rawoutput">"Show ip mroute" Raw Output</a> </li> </ul> <div id="myTabContent" class="tab-content"> <div class="tab-pane active" id="quickstats"> <div class="row"> <div class="col-lg-6"> <br> {% for dict_item in parsed_output %} {% for hostname, value in dict_item.items() %} <br> <p><strong>Hostname: </strong> {{ hostname }}</p> {% for i in dict_item[hostname] %} <p><strong>Multicast Groups: </strong> {{ i['multicast_group_ip'] }}</p> {% endfor %} {% endfor %} {% endfor %} </div> <div class="col-lg-6"> <br> </div> </div> </div> <div class="tab-pane" id="portdetail"> <div class="row"> <div class="col-lg-6"> <br> {% for dict_item in parsed_output %} {% for hostname, value in dict_item.items() %} <br> <p><strong>Hostname: </strong> {{ hostname }}</p> {% for i in dict_item[hostname] %} <p><strong>Multicast Groups: </strong> {{ i['multicast_group_ip'] }} <br><strong>Uptime: </strong> {{ i['up_time'] }} <br><strong>Incoming Interface: </strong> {{ i['incoming_interface'] }} <br><strong>RPF Neighbour IP: </strong> {{ i['reverse_path_forwarding_neighbour_ip'] }} {% if i['outgoing_interface'] == [] %} <br><strong>Outgoing Interface: </strong> No Interfaces {% else %} <br><strong>Outgoing Interface: </strong> {{ i['outgoing_interface'] }} {% endif %} </p> {% endfor %} {% endfor %} {% endfor %} </div> </div> </div> <div class="tab-pane" id="rawoutput"> <br> {% for key,value in show_output_dict.items() %} <br><strong>{{ key }}</strong><br> <code> {% for element in value %} {{ element }}<br> {% endfor %} </code> {% endfor %} <br> </div> </div> </div> </div> {% endblock %} |
List of Dictionaries (parsed_output) Tab1
The list of dictionaries contains all of the data parsed from my TextFSM template for each Nexus switch.
0 1 2 |
[{'mcast_nexus2': [{'vrf_name': 'default', 'multicast_source_ip': '*', 'multicast_group_ip': '232.0.0.0/8', 'up_time': '6d11h', 'incoming_interface': 'Null', 'reverse_path_forwarding_neighbour_ip': '0.0.0.0', 'outgoing_interface_count': ['0'], 'outgoing_interface': [], 'outgoing_multicast_up_time': []}, {'vrf_name': 'default', 'multicast_source_ip': '*', 'multicast_group_ip': '239.0.1.2/32', 'up_time': '3d11h', 'incoming_interface': 'loopback0', 'reverse_path_forwarding_neighbour_ip': '10.1.10.1', 'outgoing_interface_count': ['1'], 'outgoing_interface': ['Ethernet1/2'], 'outgoing_multicast_up_time': ['3d11h,']}, {'vrf_name': 'default', 'multicast_source_ip': '172.16.2.200/32', 'multicast_group_ip': '239.0.1.2/32', 'up_time': '3d11h', 'incoming_interface': 'Ethernet1/1', 'reverse_path_forwarding_neighbour_ip': '10.1.1.1', 'outgoing_interface_count': ['0'], 'outgoing_interface': [], 'outgoing_multicast_up_time': []}, {'vrf_name': 'default', 'multicast_source_ip': '*', 'multicast_group_ip': '239.255.255.250/32', 'up_time': '4d20h', 'incoming_interface': 'loopback0', 'reverse_path_forwarding_neighbour_ip': '10.1.10.1', 'outgoing_interface_count': ['2'], 'outgoing_interface': ['Ethernet1/2', 'Ethernet1/1'], 'outgoing_multicast_up_time': ['4d20h,', '4d20h,']}]}, {'mcast_nexus4': [{'vrf_name': 'default', 'multicast_source_ip': '*', 'multicast_group_ip': '232.0.0.0/8', 'up_time': '6d11h', 'incoming_interface': 'Null', 'reverse_path_forwarding_neighbour_ip': '0.0.0.0', 'outgoing_interface_count': ['0'], 'outgoing_interface': [], 'outgoing_multicast_up_time': []}, {'vrf_name': 'default', 'multicast_source_ip': '*', 'multicast_group_ip': '239.0.1.2/32', 'up_time': '3d11h', 'incoming_interface': 'Ethernet1/2', 'reverse_path_forwarding_neighbour_ip': '10.1.2.1', 'outgoing_interface_count': ['1'], 'outgoing_interface': ['Vlan50'], 'outgoing_multicast_up_time': ['3d11h,']}, {'vrf_name': 'default', 'multicast_source_ip': '172.16.2.200/32', 'multicast_group_ip': '239.0.1.2/32', 'up_time': '3d11h', 'incoming_interface': 'Vlan16', 'reverse_path_forwarding_neighbour_ip': '10.1.6.1', 'outgoing_interface_count': ['1'], 'outgoing_interface': ['Vlan50'], 'outgoing_multicast_up_time': ['3d11h,']}, {'vrf_name': 'default', 'multicast_source_ip': '*', 'multicast_group_ip': '239.255.255.250/32', 'up_time': '4d20h', 'incoming_interface': 'Ethernet1/2', 'reverse_path_forwarding_neighbour_ip': '10.1.2.1', 'outgoing_interface_count': ['1'], 'outgoing_interface': ['Vlan50'], 'outgoing_multicast_up_time': ['4d20h,']}]}, {'mcast_nexus1': [{'vrf_name': 'default', 'multicast_source_ip': '*', 'multicast_group_ip': '232.0.0.0/8', 'up_time': '6d11h', 'incoming_interface': 'Null', 'reverse_path_forwarding_neighbour_ip': '0.0.0.0', 'outgoing_interface_count': ['0'], 'outgoing_interface': [], 'outgoing_multicast_up_time': []}, {'vrf_name': 'default', 'multicast_source_ip': '172.16.2.200/32', 'multicast_group_ip': '239.0.1.2/32', 'up_time': '3d11h', 'incoming_interface': 'Vlan20', 'reverse_path_forwarding_neighbour_ip': '172.16.2.200', 'outgoing_interface_count': ['1'], 'outgoing_interface': ['Vlan16'], 'outgoing_multicast_up_time': ['2d13h,']}, {'vrf_name': 'default', 'multicast_source_ip': '*', 'multicast_group_ip': '239.255.255.250/32', 'up_time': '4d20h', 'incoming_interface': 'Ethernet1/1', 'reverse_path_forwarding_neighbour_ip': '10.1.1.2', 'outgoing_interface_count': ['1'], 'outgoing_interface': ['Vlan20'], 'outgoing_multicast_up_time': ['4d20h,']}]}, {'mcast_nexus3': [{'vrf_name': 'default', 'multicast_source_ip': '*', 'multicast_group_ip': '232.0.0.0/8', 'up_time': '2d11h', 'incoming_interface': 'Null', 'reverse_path_forwarding_neighbour_ip': '0.0.0.0', 'outgoing_interface_count': ['0'], 'outgoing_interface': [], 'outgoing_multicast_up_time': []}]}] |
In the HTML file I am using Jinja to;
- Pull out the hostname values mcast_Nexus1,2,3,4
- Pull out the multicast_group_ip for each hostname
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<div class="tab-pane active" id="quickstats"> <div class="row"> <div class="col-lg-6"> <br> {% for dict_item in parsed_output %} {% for hostname, value in dict_item.items() %} <br> <p><strong>Hostname: </strong> {{ hostname }}</p> {% for i in dict_item[hostname] %} <p><strong>Multicast Groups: </strong> {{ i['multicast_group_ip'] }}</p> {% endfor %} {% endfor %} {% endfor %} </div> <div class="col-lg-6"> <br> </div> </div> </div> |
List of Dictionaries (parsed_output) Tab 2
For the next tab I have used a similar method as in the first tab, oulling out the hostname and thenthe details for that hostname.
An addition here is that not all dictionary keys are populated so there are if statements in here that can display differen text in the HTML page based off what is in the dictionary or not.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<div class="tab-pane" id="portdetail"> <div class="row"> <div class="col-lg-6"> <br> {% for dict_item in parsed_output %} {% for hostname, value in dict_item.items() %} <br> <p><strong>Hostname: </strong> {{ hostname }}</p> {% for i in dict_item[hostname] %} <p><strong>Multicast Groups: </strong> {{ i['multicast_group_ip'] }} <br><strong>Uptime: </strong> {{ i['up_time'] }} <br><strong>Incoming Interface: </strong> {{ i['incoming_interface'] }} <br><strong>RPF Neighbour IP: </strong> {{ i['reverse_path_forwarding_neighbour_ip'] }} {% if i['outgoing_interface'] == [] %} <br><strong>Outgoing Interface: </strong> No Interfaces {% else %} <br><strong>Outgoing Interface: </strong> {{ i['outgoing_interface'] }} {% endif %} </p> {% endfor %} {% endfor %} {% endfor %} </div> </div> </div> |
Dictionary (show_output_dict) Tab 3
This tab I am showing the output from the Cisco switch with a heading of the hostname above. The output is displayed inside code tags and the heading is a paragraph, but in bold.
Again this is using a nested for loop similar to tab1 to get the hostname out.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
<div class="tab-pane" id="rawoutput"> <br> {% for key,value in show_output_dict.items() %} <br><strong>{{ key }}</strong><br> <code> {% for element in value %} {{ element }}<br> {% endfor %} </code> {% endfor %} <br> </div> |