#django #django-models #max #aggregate #django-annotate
#django #django-модели #макс . #агрегировать #django-аннотировать
Вопрос:
Я создаю приложение, которое позволяет пользователям записывать свои тренировки. Сначала они создадут упражнение (например, жим лежа), а затем заполнят форму, чтобы показать, какой вес они смогли поднять для этого конкретного упражнения. Их результаты будут отображаться под формой. Там будет много форм тренировок, относящихся ко многим различным тренировкам. Тренировки и упражнения также будут специфичны для каждого пользователя.
Вот мой models.py:
from django.contrib.auth.models import User
class Exercise(models.Model):
name = models.CharField(max_length=100)
class Workout(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE)
weight = models.DecimalField(default=0.0, max_digits=5, decimal_places=1)
exercise = models.ForeignKey(Exercise, on_delete=models.CASCADE, default=None)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
Теперь я хочу показать пользователю, каков был их максимальный подъем для каждой отдельной тренировки, но не могу понять, как получить эту информацию. Я искал ответ в Интернете, и кажется, что использование aggregate или annotate может быть правильным решением, но я перепробовал кучу разных запросов и не могу заставить его показать то, что мне нужно. Надеюсь, кто-нибудь может помочь.
Ответ №1:
Вы можете пометить свои Exercise
s максимальным весом для Workout
s данного пользователя с помощью:
from django.db.models import Max
Exercise.objects.filter(
workout__user=someprofile
).annotate(
max_weight=Max('workout__weight')
)
Exercise
Объекты, возникающие из этого набора запросов, будут иметь дополнительный атрибут .max_weight
, который содержит максимальный вес для этого упражнения someprofile
.
Комментарии:
1. Спасибо, Виллем, не могли бы вы просто объяснить, где я должен ввести этот блок кода?
2. @sgt_pepper85: в представлении, где вы хотите указать максимальные веса для каждого выполнения.
3. Да, я получаю ошибку FieldError
Cannot resolve keyword 'weight' into field
4. @sgt_pepper85: извините, допустил опечатку: это
'workout__weight'
5.@sgt_pepper85:
m_weight
это не одинExercise
, это всеExercise
, что сделал пользователь. Таким образом, вы повторяете упражнения и печатаетеmax_weight
, so{% for exc in m_weight %}{{ exc }}: {{ exc.max_weight }}{% endfor %}
.
Ответ №2:
Учитывая пользователя, вам нужно снабдить каждое упражнение комментарием с максимальным весом.
from django.db.models import Max
user.workout_set.values('exercise').annotate(max_weight=Max('weight'))
это должно сработать
Комментарии:
1. Привет, большое спасибо за ответ. Итак, этот запрос входит в мою модель тренировки? Должно ли это быть частью метода или как есть? И как я тогда получу доступ к этим данным в моем шаблоне?
2. Это вернет набор запросов с каждым результатом, содержащим
exercise
max_weight
значения и . Я не очень хорошо знаком с использованием шаблонов, но я думаю, что вы можете выполнить итерацию по этому набору запросов в шаблоне с{% for i in some_list %}
синтаксисом.3. Извините, я все еще не понимаю, куда поместить эту строку кода.
Ответ №3:
Вместо использования агрегации простой способ сделать это — упорядочить, а затем использовать distinct при выполнении упражнения:
Workout.objects.filter(user=user)
.order_by('exercise', '-weight')
.distinct('exercise')
Это даст вам список всех тренировок с наибольшим весом для каждого упражнения.
Комментарии:
1. Привет, спасибо, Марти. Я попытался добавить ваш код в свой
get_context_data
метод на мой взгляд, но мой шаблон возвращаетTemplateSyntaxError Could not parse the remainder: '-weight' from 'max-weight'
2. Это
TemplateSyntaxError
так, что очень вероятно, что это ошибка в вашем шаблоне (особенно если вы его изменили). Кроме того, обратите внимание, что это выражение возвращает набор запросов к тренировкам (тем, у которых самый большой вес); так что вашmax-weight
, вероятно, должен быть простоweight
.3. Извините за это, я выбрал неправильное имя переменной. Однако теперь я получаю
NotSupportedError DISTINCT ON fields is not supported by this database backend
4. Эта ошибка не требует пояснений: серверная часть базы данных, которую вы используете, не поддерживает эту
.distinct('exercise')
часть.