Как найти наибольшее значение поля ForeignKey для конкретного пользователя в Django

#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') часть.