You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中对多对多字段进行分组的实现方法

解决Django按类别分组展示用户关联练习的问题

首先先修正你模型里的一个明显错误:CategoryExercisesThrough类里的category字段关联的是ExerciseCollections,但你定义的类别模型是ExerciseCategory,这会导致数据库外键错误,改成下面这样:

class CategoryExercisesThrough(models.Model): #Through table for the many-to-many relationship between ExerciseCategory and Exercise
    category= models.ForeignKey(ExerciseCategory, on_delete=models.CASCADE)
    exercise = models.ForeignKey(Exercise, on_delete=models.CASCADE)

接下来是核心需求:获取指定用户的所有关联练习,并按类别分组整理成{类别名称: [练习列表]}的结构。

方法一:视图中手动整理分组数据

在视图函数里先查询目标用户的所有UserExercises,再遍历每个练习及其关联的类别,将练习归类到对应类别的列表中:

from django.shortcuts import render
from .models import UserExercises

def user_exercises_by_category(request, user_id):
    # 获取指定用户的所有关联练习,预加载练习对象避免N+1查询
    user_exercises = UserExercises.objects.filter(user_id=user_id).select_related('exercise')
    # 初始化分组字典
    category_exercises = {}
    
    for ue in user_exercises:
        exercise = ue.exercise
        # 遍历当前练习关联的所有类别
        for category in exercise.category.all():
            # 若类别不在字典中,先创建空列表
            if category.name not in category_exercises:
                category_exercises[category.name] = []
            # 避免同一练习重复加入同一类别列表
            if exercise not in category_exercises[category.name]:
                category_exercises[category.name].append(exercise)
    
    return render(request, 'your_template.html', {'category_exercises': category_exercises})

方法二:用ORM聚合优化查询(数据量大时更高效)

直接查询用户关联的所有练习,预加载关联类别,再做分组整理:

from django.shortcuts import render
from .models import Exercise

def user_exercises_by_category(request, user_id):
    # 查询用户关联的所有练习,预加载类别减少数据库请求
    exercises = Exercise.objects.filter(assignee__id=user_id).prefetch_related('category').distinct()
    
    category_exercises = {}
    for exercise in exercises:
        for category in exercise.category.all():
            if category.name not in category_exercises:
                category_exercises[category.name] = []
            category_exercises[category.name].append(exercise)
    
    return render(request, 'your_template.html', {'category_exercises': category_exercises})

模板中渲染分组数据

在模板里通过循环遍历分组后的字典,按类别展示对应的练习:

{% for category_name, exercises in category_exercises.items %}
    <h3>{{ category_name }}</h3>
    <ul>
        {% for exercise in exercises %}
            <li>{{ exercise.name }}</li> <!-- 替换成Exercise实际需要展示的字段 -->
        {% endfor %}
    </ul>
{% empty %}
    <p>该用户暂无关联练习</p>
{% endfor %}

额外提示

  • 若需要类别按名称排序,可在视图里对字典项排序后再传给模板:sorted_categories = sorted(category_exercises.items(), key=lambda x: x[0]),模板遍历sorted_categories即可
  • 如果练习可能重复关联同一用户,记得在查询时加上.distinct()去重

内容的提问来源于stack exchange,提问作者Alessio Giardina

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 06:10:34