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

Django多对多模型关联示例:健身APP模型设计与数据操作

健身APP:Exercise与MuscleGroup多对多关联实现方案

一、模型类编写(以Django ORM为例)

针对需求,我们需要给MuscleGroup定义基础信息,给Exercise区分主要目标肌群和次要目标肌群两个多对多关联,通过related_name实现清晰的反向查询逻辑:

from django.db import models

class MuscleGroup(models.Model):
    name = models.CharField(max_length=50, unique=True, verbose_name="肌群名称")

    def __str__(self):
        return self.name

class Exercise(models.Model):
    name = models.CharField(max_length=100, unique=True, verbose_name="动作名称")
    primary_muscles = models.ManyToManyField(
        MuscleGroup,
        related_name="primary_exercises",
        verbose_name="主要目标肌群",
        help_text="该动作主要刺激的肌群"
    )
    secondary_muscles = models.ManyToManyField(
        MuscleGroup,
        related_name="secondary_exercises",
        blank=True,
        verbose_name="次要目标肌群",
        help_text="该动作辅助刺激的肌群"
    )

    def __str__(self):
        return self.name

说明:

  • 两个ManyToManyField分别绑定主次肌群,避免混在一起难以区分
  • related_name让反向查询更直观:比如通过肌群可以直接获取「以它为主要目标的动作」或「以它为次要目标的动作」

二、数据库填充脚本

方式1:Django Shell临时填充

在项目根目录执行python manage.py shell,然后运行以下代码:

from your_app_name.models import MuscleGroup, Exercise

# 批量创建肌群
muscle_data = ["胸肌", "背阔肌", "肱三头肌", "肱二头肌", "肩部", "股四头肌", "臀大肌", "核心肌群"]
muscle_groups = {name: MuscleGroup.objects.create(name=name) for name in muscle_data}

# 创建动作并关联肌群
bench_press = Exercise.objects.create(name="杠铃卧推")
bench_press.primary_muscles.add(muscle_groups["胸肌"])
bench_press.secondary_muscles.add(muscle_groups["肱三头肌"], muscle_groups["肩部"])

pull_up = Exercise.objects.create(name="引体向上")
pull_up.primary_muscles.add(muscle_groups["背阔肌"])
pull_up.secondary_muscles.add(muscle_groups["肱二头肌"], muscle_groups["肩部"])

lunge = Exercise.objects.create(name="箭步蹲")
lunge.primary_muscles.add(muscle_groups["股四头肌"], muscle_groups["臀大肌"])
lunge.secondary_muscles.add(muscle_groups["核心肌群"])

方式2:可复用的管理命令

在APP目录下创建management/commands/populate_fitness_data.py,编写可重复执行的填充脚本:

from django.core.management.base import BaseCommand
from your_app_name.models import MuscleGroup, Exercise

class Command(BaseCommand):
    help = "批量填充健身动作与肌群数据"

    def handle(self, *args, **options):
        # 开发环境可清空旧数据(生产环境注释)
        MuscleGroup.objects.all().delete()
        Exercise.objects.all().delete()

        # 创建肌群
        muscle_list = ["胸肌", "背阔肌", "肱三头肌", "肱二头肌", "肩部", "股四头肌", "臀大肌", "核心肌群"]
        muscle_map = {name: MuscleGroup.objects.create(name=name) for name in muscle_list}

        # 定义动作数据
        exercise_list = [
            {
                "name": "杠铃卧推",
                "primary": ["胸肌"],
                "secondary": ["肱三头肌", "肩部"]
            },
            {
                "name": "引体向上",
                "primary": ["背阔肌"],
                "secondary": ["肱二头肌", "肩部"]
            },
            {
                "name": "箭步蹲",
                "primary": ["股四头肌", "臀大肌"],
                "secondary": ["核心肌群"]
            },
            {
                "name": "哑铃肩推",
                "primary": ["肩部"],
                "secondary": ["肱三头肌", "核心肌群"]
            }
        ]

        # 批量创建动作并关联肌群
        for ex_data in exercise_list:
            exercise = Exercise.objects.create(name=ex_data["name"])
            exercise.primary_muscles.add(*[muscle_map[name] for name in ex_data["primary"]])
            exercise.secondary_muscles.add(*[muscle_map[name] for name in ex_data["secondary"]])

        self.stdout.write(self.style.SUCCESS("健身数据填充完成!"))

执行命令即可完成填充:

python manage.py populate_fitness_data

三、字段访问测试代码

通过以下代码验证正向/反向查询是否正常:

from your_app_name.models import Exercise, MuscleGroup

# 正向查询:通过动作获取主次肌群
bench_press = Exercise.objects.get(name="杠铃卧推")
print(f"动作名称:{bench_press.name}")
print(f"主要肌群:{', '.join(mg.name for mg in bench_press.primary_muscles.all())}")
print(f"次要肌群:{', '.join(mg.name for mg in bench_press.secondary_muscles.all())}")

# 反向查询:通过肌群获取关联动作
chest = MuscleGroup.objects.get(name="胸肌")
print(f"\n以胸肌为主要目标的动作:{', '.join(ex.name for ex in chest.primary_exercises.all())}")

shoulders = MuscleGroup.objects.get(name="肩部")
print(f"以肩部为次要目标的动作:{', '.join(ex.name for ex in shoulders.secondary_exercises.all())}")

# 多条件查询:筛选包含指定肌群的动作
from django.db.models import Q
target_exercises = Exercise.objects.filter(
    Q(primary_muscles__name="核心肌群") | Q(secondary_muscles__name="核心肌群")
).distinct()
print(f"\n涉及核心肌群的动作:{', '.join(ex.name for ex in target_exercises)}")

运行后会输出清晰的关联数据,验证多对多关系的正确性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 17:12:50