如何用Jinja从元组键字典动态构建HTML表格
Got it, let's walk through how to build a dynamic HTML table from your specific data structure using Jinja. I'll break this down into actionable steps with code examples you can adapt directly:
Step 1: Confirm Your Data Structure
First, let's align on your data setup. You’ve got a dictionary where keys are tuples like ('Item', 8), and values are a Components_data namedtuple with these fields:
base_quantity: Numeric base amountitems_data: Nested dictionary (string keys, list values with two numeric entries each)price_labor: Numeric labor costtotal: Total calculated cost
We’ll start by defining the namedtuple in Python to match your structure:
from collections import namedtuple Components_data = namedtuple('Components_data', ['base_quantity', 'items_data', 'price_labor', 'total'])
Step 2: Prepare Sample Data
Let’s replicate your example (plus an extra entry to test scalability):
data_dict = { ('Item', 8): Components_data( base_quantity=63.0, items_data={'830927': [1.0, 14.851799999999999], '831103': [0.37170000000000003, 0.6972720300000002]}, price_labor=374.21824212, total=389.76731415 ), ('Item', 9): Components_data( base_quantity=45.0, items_data={'720115': [2.5, 22.34], '720201': [1.1, 5.67]}, price_labor=250.0, total=278.01 ) }
Step 3: Write the Jinja Template
I’ll share two template options depending on how you want to display the data:
Option 1: Clean Merged Cells (Avoid Repetition)
This uses rowspan to group component rows under their parent item, making the table easier to scan:
<table border="1" cellpadding="8" cellspacing="0"> <thead> <tr> <th>Item Category</th> <th>Item ID</th> <th>Base Quantity</th> <th>Component ID</th> <th>Component Qty</th> <th>Component Value</th> <th>Labor Price</th> <th>Total Cost</th> </tr> </thead> <tbody> {% for item_key, comp_data in data.items() %} {% set component_count = comp_data.items_data|length %} {% for comp_id, comp_details in comp_data.items_data.items() %} <tr> <!-- Only show parent item info on the first component row --> {% if loop.first %} <td rowspan="{{ component_count }}">{{ item_key[0] }}</td> <td rowspan="{{ component_count }}">{{ item_key[1] }}</td> <td rowspan="{{ component_count }}">{{ comp_data.base_quantity }}</td> <td rowspan="{{ component_count }}">{{ comp_data.price_labor }}</td> <td rowspan="{{ component_count }}">{{ comp_data.total }}</td> {% endif %} <td>{{ comp_id }}</td> <td>{{ comp_details[0] }}</td> <td>{{ comp_details[1] }}</td> </tr> {% endfor %} {% endfor %} </tbody> </table>
Option 2: Full Row Details (No Merging)
If you prefer every row to include complete item and component info (ideal for exports or filtering), use this simpler template:
<table border="1" cellpadding="8" cellspacing="0"> <thead> <tr> <th>Item Category</th> <th>Item ID</th> <th>Base Quantity</th> <th>Component ID</th> <th>Component Qty</th> <th>Component Value</th> <th>Labor Price</th> <th>Total Cost</th> </tr> </thead> <tbody> {% for item_key, comp_data in data.items() %} {% for comp_id, comp_details in comp_data.items_data.items() %} <tr> <td>{{ item_key[0] }}</td> <td>{{ item_key[1] }}</td> <td>{{ comp_data.base_quantity }}</td> <td>{{ comp_id }}</td> <td>{{ comp_details[0] }}</td> <td>{{ comp_details[1] }}</td> <td>{{ comp_data.price_labor }}</td> <td>{{ comp_data.total }}</td> </tr> {% endfor %} {% endfor %} </tbody> </table>
Step 4: Render the Template with Python
Use Jinja’s Environment to load and render the template with your data:
from jinja2 import Environment, BaseLoader # Replace with your chosen template string (Option 1 or 2 above) template_str = """[INSERT TEMPLATE HERE]""" # Set up Jinja environment env = Environment(loader=BaseLoader()) template = env.from_string(template_str) # Generate the HTML output html_output = template.render(data=data_dict) # Save to file or print the result print(html_output) # with open('item_components_table.html', 'w') as f: # f.write(html_output)
Quick Tips
- Tuple key access: In Jinja, use
item_key[0]anditem_key[1]to pull the category and ID from your tuple keys. - Namedtuple fields: Directly access fields like
comp_data.base_quantity—namedtuples are attribute-accessible just like regular objects. - Nested dictionary loops: Iterate over
comp_data.items_data.items()to get each component’s ID and its associated quantity/value pair.
内容的提问来源于stack exchange,提问作者Espoir Murhabazi

