如何在Django中按字段将模型数据分组为多张表格?
Django按字段分组展示数据实现方案
问题还原
假设我有如下表格:
| Name | Age | Country |
|---|---|---|
| A | 17 | England |
| B | 18 | Swiss |
| C | 19 | Italy |
| D | 19 | Italy |
| E | 19 | England |
表格中任意列包含唯一值,比如Country列有3个唯一值(England、Swiss、Italy),Age列有3个唯一值(17、18、19)。希望通过Django查询按Country列分组展示,效果如下:
England
| Name | Age | Country |
|---|---|---|
| A | 17 | England |
| E | 19 | England |
Italy
| Name | Age | Country |
|---|---|---|
| C | 19 | Italy |
| D | 19 | Italy |
Swiss
| Name | Age | Country |
|---|---|---|
| B | 18 | Swiss |
实现步骤
1. 模型定义
先确保你的Django模型对应表格结构,示例如下:
from django.db import models class Person(models.Model): name = models.CharField(max_length=50) age = models.IntegerField() country = models.CharField(max_length=50) def __str__(self): return self.name
2. 视图层处理数据
提供两种实现方式,按需选择:
方式一:基础分组(逻辑直观,小数据量适用)
from django.shortcuts import render from .models import Person def grouped_persons(request): # 获取所有唯一国家并排序 countries = Person.objects.values_list('country', flat=True).distinct().order_by('country') # 构建国家-对应数据的字典 grouped_data = {country: Person.objects.filter(country=country) for country in countries} return render(request, 'grouped_persons.html', {'grouped_data': grouped_data})
方式二:内存分组(性能更优,大数据量推荐)
利用itertools.groupby实现单次查询后内存分组,需先按分组字段排序:
from django.shortcuts import render from .models import Person from itertools import groupby def grouped_persons(request): # 先按country排序,确保groupby能正确分组 persons = Person.objects.order_by('country') # 按country字段分组 grouped_data = groupby(persons, key=lambda x: x.country) return render(request, 'grouped_persons.html', {'grouped_data': grouped_data})
3. 模板层渲染展示
在grouped_persons.html模板中渲染分组数据:
对应方式一的模板代码
{% for country, persons in grouped_data.items %} >{{ country }} <table border="1"> <tr> <th>Name</th> <th>Age</th> <th>Country</th> </tr> {% for person in persons %} <tr> <td>{{ person.name }}</td> <td>{{ person.age }}</td> <td>{{ person.country }}</td> </tr> {% endfor %} </table> <br> {% endfor %}
对应方式二的模板代码
{% for country, persons in grouped_data %} >{{ country }} <table border="1"> <tr> <th>Name</th> <th>Age</th> <th>Country</th> </tr> {% for person in persons %} <tr> <td>{{ person.name }}</td> <td>{{ person.age }}</td> <td>{{ person.country }}</td> </tr> {% endfor %} </table> <br> {% endfor %}
注意事项
- 方式一会执行N+1次数据库查询(N为国家数量),适合数据量较小的场景;
- 方式二仅执行1次查询,在内存中完成分组,性能更优,但必须保证查询集已按分组字段排序,否则
groupby无法正确分组。
内容的提问来源于stack exchange,提问作者Abdullah Sokrab
相关产品推荐
相关产品推荐

