首先,我建议通读 Django models docs 以了解模型代表什么以及它们是如何工作的。
为了解决您的问题,我认为您已经正确识别了创建模型所需的所有信息,所以让我们逐步了解它们。
架构
退后一步思考应用中的实体会很有帮助。确定它们是什么,它们拥有什么属性以及这些属性中的哪些是atomic,即不能是它们自己的实体。
-
锻炼 - 您提到要跟踪锻炼,每个锻炼都有名称、体重、日期和锻炼。除了 exercises 之外的所有这些属性似乎都是原子的,因为它们可以用基本数据类型(字符串、浮点数、日期时间等)表示。此外,一个锻炼可以有many exercises,表示我们需要将它抽象成它自己的实体。
-
练习 - 您确定练习是预设的,需要有名称和标签。名称是我们可以用字符串表示的东西,但是一个练习可以有多个标签,这意味着它不是原子的(具有one-to-many 关系)。这意味着我们需要将其提取到自己的实体中。
-
标签 - 根据您的说法,标签仅具有一个属性,该属性是可以用字符串表示的名称。一个标签可以属于多个练习。
您可能想知道我们将每次锻炼的次数、组数和重量数据存储在哪里。这实际上需要一个额外的实体来存储运动和锻炼之间的多对多关系。我们称之为Workout-Exercise。
有了这些信息,我们可以画出Entity Relationship Diagram:
这为我们提供了开始创建 Django 模型所需的内容。
型号
让我们从Exercise 和Tag 实体开始。我们可以简单地将这些直接翻译成 Django 模型:
from django.db import models
class Tag(models.Model):
name = models.CharField(max_length=200)
class Exercise(models.Model):
name = models.CharField(max_length=200)
tags = models.ManyToManyField(Tag)
在这里,我们创建了两个模型,并在 Exercise 和 Tag 之间指定了多对多关系。这意味着一个Exercise 对象可以有许多Tag 对象,例如您可以调用exercise.tags.all() 来获取给定Exercise 对象的所有标签。
当我们创建Workout-Exercise 实体时,棘手的部分就来了。当我们在 Django 中使用ManyToManyField 时,它通常会自动创建一个我们看不到的映射模型/表。但是,如果我们想要存储有关这些关系的额外信息(就像我们在用例中所做的那样),我们必须使用 through model。
在这个模型上,我们必须为我们要链接的模型定义两个外键以及我们想要存储的额外字段数据的数据类型。在这种情况下,外键是Workout 和Exercise,额外的数据是reps、sets 和weight。因此,模型定义可能如下所示:
class WorkoutExercise(models.Model):
workout = models.ForeignKey(
'Workout',
on_delete=models.CASCADE,
)
exercise = models.ForeignKey(
Exercise,
on_delete=models.CASCADE,
)
reps = models.IntegerField()
sets = models.IntegerField()
weight = models.DecimalField(max_digits=5, decimal_places=2)
class Workout(models.Model):
name = models.CharField(max_length=200)
body_weight = models.DecimalField(max_digits=5, decimal_places=2)
date = models.DateTimeField(auto_now_add=True)
exercises = models.ManyToManyField(
Exercise,
through=WorkoutExercise
)
如果您对我推荐的任何模型数据类型选择感到困惑,请查看Django model docs。
通过此设置,您应该能够访问和插入您需要的所有数据。如果您需要有关如何访问任何多对多关系数据的更多信息,请查看 Django many-to-many docs。
来源