Django — связь «Многие ко многим» с тренировками и упражнениями

#django #django-models

#django #django-модели

Вопрос:

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

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

У каждой тренировки есть название, вес тела, дата и упражнения.

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

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

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

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

Изображение дизайна

Ответ №1:

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

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

Архитектура

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

  • Тренировка — Вы упомянули, что хотите отслеживать тренировки, каждая из которых имеет название, вес тела, дату и упражнения. Все эти атрибуты, за исключением упражнений, кажутся атомарными, поскольку они могут быть представлены с помощью основных типов данных (строки, числа с плавающей точкой, даты и т. Д.). Более того, в одной тренировке может быть много упражнений, указывающих на то, что нам нужно абстрагировать ее в свою собственную сущность.
  • Упражнение — вы определили, что упражнения предварительно настроены и должны иметь название и теги. Имя — это то, что мы можем представить с помощью строки, однако одно упражнение может иметь несколько тегов, что означает, что оно не является атомарным (имеет отношение «один ко многим«). Это означает, что нам нужно извлечь его в его собственную сущность.
  • Тег — из того, что вы сказали, у тега просто есть один атрибут, который является именем, которое может быть представлено строкой. Один тег может принадлежать многим упражнениям.

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

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

ERD для идентифицированных объектов.

Это дает нам то, что нам нужно, чтобы начать создавать модели 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 and Exercise , а дополнительными данными являются reps sets and 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 .

Источники