Django - отношения "многие ко многим" с тренировками и упражнениями
В настоящее время я застрял на том, как сделать следующее:
Я хочу отслеживать тренировки и видеть прогресс в выполнении упражнений.
Каждая тренировка имеет название, вес тела, дату и упражнения.
Я хочу выбирать упражнения при добавлении тренировок (упражнения уже предварительно созданы с именем и некоторыми тегами), однако, каждая тренировка отличается, то есть повторения, сеты и вес для упражнения каждый раз разные.
Я не уверен, как сделать модель для этого.
Я добавил изображение простого дизайна, который я сделал, чтобы показать, что мне нужно
Надеюсь, кто-нибудь сможет мне помочь, я уверен, что это простое решение, однако, мой мозг застрял на данный момент.
Прежде всего, я бы рекомендовал прочитать документацию по Django models docs, чтобы получить представление о том, что представляют собой модели и как они работают.
Чтобы ответить на ваш вопрос, я думаю, вы правильно определили всю информацию, необходимую для создания моделей, поэтому давайте пройдемся по ним шаг за шагом.
Архитектура
Полезно сделать шаг назад и подумать о сущностях в вашем приложении. Определите, чем они являются, какими атрибутами обладают и какие из этих атрибутов являются атомарными, т.е. не могут быть собственной сущностью.
Workout - Вы упомянули, что хотите отслеживать тренировки, каждая из которых имеет имя, вес тела, дату и упражнения. Все эти атрибуты, за исключением exercises, кажутся атомарными, поскольку они могут быть представлены с помощью фундаментальных типов данных (строки, плавающие значения, даты и т.д.). Более того, одна тренировка может иметь множество упражнений, что указывает на необходимость абстрагировать ее в отдельную сущность.
Упражнение - Вы определили, что упражнения заданы заранее и должны иметь имя и теги. Название - это то, что мы можем представить строкой, однако одно упражнение может иметь несколько тегов, что означает, что оно не является атомарным (имеет отношения один-ко-многим). Это означает, что нам нужно извлечь его в отдельную сущность.
Тег - Из того, что вы сказали, тег просто имеет один атрибут, который является именем, которое может быть представлено строкой. Один тег может принадлежать многим упражнениям.
Возможно, вам интересно, где мы храним данные о повторениях, сетах и весе для каждого упражнения в каждой тренировке. На самом деле для этого потребуется дополнительная сущность, которая будет хранить отношения "многие-ко-многим" между упражнениями и тренировками. Назовем ее Workout-Exercise.
С этой информацией мы могли бы нарисовать диаграмму отношений между предприятиями <
Это дает нам все необходимое, чтобы начать создавать модели 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
. Когда мы используем ManyToManyField в Django, он обычно автоматически создает модель/таблицу отображения, которую мы не видим. Однако в случае, когда мы хотим хранить дополнительную информацию об этих отношениях (как в нашем примере), мы должны использовать сквозную модель.
В этой модели мы должны определить два внешних ключа для моделей, которые мы связываем, а также типы данных для дополнительных полей, которые мы хотим хранить. В данном случае внешними ключами являются 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.
Источники