Django模板循环优化:实现参与者仅显示一次并关联所有投票者
解决Django中重复显示参与者并聚合投票者的问题
问题场景
现有Participanti(被投票者)和Restrictie(投票记录)模型,Restrictie记录了被投票者与投票者的关联。在模板中直接遍历Restrictie所有数据时,同一参与者会随每条投票记录重复显示,期望实现每个参与者仅显示一次,旁侧列出所有对应的投票者,格式如「参与者姓名 -(投票者1姓名,投票者2姓名……)」。
现有代码
models.py
class Participanti(models.Model): campanievot = models.ForeignKey(Campanie, on_delete=models.CASCADE) nume_participant = models.CharField(max_length=200, verbose_name='nume') dep_participant = models.CharField(max_length=200, verbose_name='departament') votes = models.IntegerField(default=0) def __str__(self): return self.nume_participant class Meta: verbose_name = 'Participanti' verbose_name_plural = 'Participanti' class Restrictie(models.Model): participanti = models.ForeignKey(Participanti,on_delete=models.CASCADE, verbose_name='Votat') votant = models.ForeignKey(UserVot,on_delete=models.CASCADE) def __str__(self): return str(self.participanti) class Meta: verbose_name = 'Voturi efectuate' verbose_name_plural = 'Voturi efectuate'
views.py
def rezultate(request): cineavotat = Restrictie.objects.all() # 其他逻辑... return render(request, 'your_template.html', {'cineavotat': cineavotat})
原模板代码(存在重复问题)
{% for p in cineavotat %} {{ p.participanti }} - {{ p.votant}} {% endfor %}
解决方案
方案1:使用Django模板regroup标签(无需修改视图)
利用Django内置的regroup标签,直接在模板中按参与者分组,无需改动视图层代码:
{% regroup cineavotat by participanti as participanti_groups %} {% for group in participanti_groups %} {{ group.grouper.nume_participant }} - ( {% for restrictie in group.list %} {{ restrictie.votant }}{% if not forloop.last %}, {% endif %} {% endfor %} ) {% endfor %}
regroup cineavotat by participanti as participanti_groups:将所有投票记录按participanti字段分组,得到以参与者为键、对应投票记录列表为值的分组集合group.grouper:代表分组的参与者对象,直接调用nume_participant获取姓名- 内层循环遍历该参与者的所有投票记录,提取投票者姓名并拼接格式
方案2:视图层预聚合数据(性能更优)
如果数据量较大,推荐在视图层通过ORM预获取并聚合数据,减少模板层的逻辑处理,提升性能:
修改views.py
from django.db.models import Prefetch def rezultate(request): # 预获取每个参与者对应的所有投票记录,并关联查询投票者信息 participanti_list = Participanti.objects.prefetch_related( Prefetch( 'restrictie_set', queryset=Restrictie.objects.select_related('votant'), to_attr='votanti_list' ) ).all() return render(request, 'your_template.html', {'participanti_list': participanti_list})
prefetch_related:预加载参与者关联的所有Restrictie记录select_related('votant'):同时关联查询投票者的用户信息,避免N+1查询to_attr='votanti_list':将关联的投票记录存入自定义属性,方便模板调用
对应模板代码
{% for participant in participanti_list %} {{ participant.nume_participant }} - ( {% for restrictie in participant.votanti_list %} {{ restrictie.votant }}{% if not forloop.last %}, {% endif %} {% endfor %} ) {% endfor %}
内容的提问来源于stack exchange,提问作者Robert Murariu
相关产品推荐
相关产品推荐

