Django - отношения "многие ко многим" с тренировками и упражнениями

В настоящее время я застрял на том, как сделать следующее:

Я хочу отслеживать тренировки и видеть прогресс в выполнении упражнений.

Каждая тренировка имеет название, вес тела, дату и упражнения.

Я хочу выбирать упражнения при добавлении тренировок (упражнения уже предварительно созданы с именем и некоторыми тегами), однако, каждая тренировка отличается, то есть повторения, сеты и вес для упражнения каждый раз разные.

Я не уверен, как сделать модель для этого.

Я добавил изображение простого дизайна, который я сделал, чтобы показать, что мне нужно

Надеюсь, кто-нибудь сможет мне помочь, я уверен, что это простое решение, однако, мой мозг застрял на данный момент.

Image Of Design

Прежде всего, я бы рекомендовал прочитать документацию по Django models docs, чтобы получить представление о том, что представляют собой модели и как они работают.

Чтобы ответить на ваш вопрос, я думаю, вы правильно определили всю информацию, необходимую для создания моделей, поэтому давайте пройдемся по ним шаг за шагом.

Архитектура

Полезно сделать шаг назад и подумать о сущностях в вашем приложении. Определите, чем они являются, какими атрибутами обладают и какие из этих атрибутов являются атомарными, т.е. не могут быть собственной сущностью.

  • Workout - Вы упомянули, что хотите отслеживать тренировки, каждая из которых имеет имя, вес тела, дату и упражнения. Все эти атрибуты, за исключением exercises, кажутся атомарными, поскольку они могут быть представлены с помощью фундаментальных типов данных (строки, плавающие значения, даты и т.д.). Более того, одна тренировка может иметь множество упражнений, что указывает на необходимость абстрагировать ее в отдельную сущность.

  • Упражнение - Вы определили, что упражнения заданы заранее и должны иметь имя и теги. Название - это то, что мы можем представить строкой, однако одно упражнение может иметь несколько тегов, что означает, что оно не является атомарным (имеет отношения один-ко-многим). Это означает, что нам нужно извлечь его в отдельную сущность.

  • Тег - Из того, что вы сказали, тег просто имеет один атрибут, который является именем, которое может быть представлено строкой. Один тег может принадлежать многим упражнениям.

Возможно, вам интересно, где мы храним данные о повторениях, сетах и весе для каждого упражнения в каждой тренировке. На самом деле для этого потребуется дополнительная сущность, которая будет хранить отношения "многие-ко-многим" между упражнениями и тренировками. Назовем ее Workout-Exercise.

С этой информацией мы могли бы нарисовать диаграмму отношений между предприятиями < следующим образом:

An ERD for the identified entities.

Это дает нам все необходимое, чтобы начать создавать модели 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.

Источники

Вернуться на верх