Django嵌套For循环问题:父循环与子循环Model.id不匹配
问题核心原因
视图层遍历场馆时,每次循环都执行了reward_positions = [],直接重置了这个列表,导致最终传入模板的reward_positions只保留了最后一个场馆的奖励程序数据,模板自然无法匹配当前循环的场馆ID。
修复方案
1. 重构视图层数据存储逻辑
将reward_positions从列表改为字典,用场馆ID作为键,存储对应场馆的所有奖励位置数据:
def list_venues(request): venue_markers = Venue.objects.filter(venue_active=True) bar_total_lenght = 100 rewards_available_per_venue = 0 reward_position_on_bar = 0 venue_data = {} # 初始化字典,而非列表 reward_positions = {} for venue in venue_markers: print(f'venue name ={venue}') venue.reward_programs = venue.venuerewardprogram.all() reward_program_per_venue = venue.reward_programs # 用列表推导式简化数据收集 reward_points_per_venue_test = [rp.points for rp in reward_program_per_venue] reward_points_per_venue_test.sort(reverse=True) highest_reward = reward_points_per_venue_test[0] if reward_points_per_venue_test else 0 if reward_program_per_venue: rewards_available_per_venue = reward_program_per_venue.count() if rewards_available_per_venue > 0: # 为当前场馆创建专属的奖励位置列表 current_venue_rewards = [] for rewardprogram in reward_program_per_venue: reward_points = rewardprogram.points # 避免除以0的异常 if highest_reward == 0: reward_position_on_bar = 0 else: reward_position_on_bar = reward_points / highest_reward current_venue_rewards.append((venue, reward_points, reward_position_on_bar)) # 将当前场馆数据存入字典,键为场馆ID reward_positions[venue.id] = current_venue_rewards print(f'Reward positions for {venue.id} = {current_venue_rewards}') context = {'reward_positions':reward_positions,'venue_data':venue_data,'venue_markers':venue_markers} return render(request,'template.html',context)
2. 修改模板层匹配逻辑
根据当前循环的venue.id,直接从字典中取出对应场馆的奖励数据:
{% load custom_filters %} <!-- 先加载自定义过滤器 --> {%for venue in venue_markers%} {%for key, value in venue_data.items%} {%if key == venue.id%} {% with venue_rewards=reward_positions|get_item:venue.id %} {% for reward_position in venue_rewards %} {{reward_position.0.id}} <!-- 现在会匹配当前场馆ID --> {{key}} {% endfor %} <div class="progress-bar bg-success" role="progressbar" style="width: {{value}}%" aria-valuenow="{{value}}" aria-valuemin="0" aria-valuemax="100"></div> {% endwith %} {%endif%} {%endfor%} {%endfor%}
注:Django模板默认没有字典取值的过滤器,需自定义:
在app的templatetags目录下创建custom_filters.py:
from django import template register = template.Library() @register.filter(name='get_item') def get_item(dictionary, key): return dictionary.get(key)
额外优化点
- 用列表推导式简化奖励点数收集,提升代码可读性
- 增加除以0的异常处理,避免无奖励数据时报错
- 移除冗余的
pass语句,精简代码
内容的提问来源于stack exchange,提问作者PhilM
相关产品推荐
相关产品推荐

