Django ORM: как сгруппировать значение и получить другое значение последнего элемента в этой группе

#python #django #annotations #django-orm

#python #django #примечания #django-orm

Вопрос:

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

По сути, я хочу сгруппировать 2 значения (user и assignment), затем взять последний элемент на основе даты и получить сумму этих баллов. Ниже описание проблемы.

С Postgres это было бы легко решить с помощью .distinct(«значение»), но, к сожалению, я не использую Postgres.

Любая помощь будет высоко оценена!!

 UserAnswer
- user
- assignment
- date
- answer
- score
 

Итак, я хочу сгруппировать все комбинации user / assignment. Затем я хочу получить оценку каждого последнего элемента в этой группе. Итак, в основном:

 user_1, assignment_1, 2019, score 1
user_1, assignment_1, 2020, score 2 <- Take this one
user_2, assignment_1, 2020, score 1
user_2, assignment_1, 2021, score 2 <- Take this one
 

Моя лучшая попытка — использовать аннотацию, но тогда у меня больше нет значения score:

 UserAnswer.objects.filter(user=student, assignment__in=assignments)
    .values("user", "assignment")
    .annotate(latest_date=Max('date'))
 

Комментарии:

1. как вы проверили, есть ли у вас оценка или нет? Я не вижу проблем с вашим запросом. вы проверили useranswer.score?

2. Спасибо, что подумали со мной. Я проверил его, и он возвращает только значение user, assignment и max date в нем.

Ответ №1:

В конце мне пришлось использовать необработанный запрос, а не ORM от django.

 subquery2 = UserAnswer.objects.raw("
        SELECT id, user_id, assignment_id, score, MAX(date) AS latest_date
        FROM soforms_useranswer 
        GROUP BY user_id, assignment_id
    ")

# the raw queryset from above raw query 
# is very similar to queryset you get from django ORM query. 
# The difference is now we add 'id' and 'score' to the fields, 
# so later we can retrieve them, like below.

    sum2= 0
    for obj in subquery2:
        print(obj.score)
        sum2  = obj.score

    print('sum2 is')
    print(sum2)

 

Здесь я предположил, что и user, и assignment являются foreinkeys . Что- то лежит внизу:

 class Assignment(models.Model):
    name = models.CharField(max_length=50)

class UserAnswer(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='answers')
    assignment = models.ForeignKey(Assignment, on_delete=models.CASCADE)
    #assignment = models.CharField(max_length=200)
    score = models.IntegerField()
    date = models.DateTimeField(default=timezone.now)
 

Комментарии:

1. Хи, спасибо за ваш ответ. Я попробовал это, но, к сожалению, я по-прежнему получаю только user, assignment и lastest_date обратно в словарь. Вот так: {‘user’: 1, ‘assignment’: 1, ‘latest_date’: datetime.datetime(2020, 11, 19, 11, 0, 41, 2356, tzinfo=<UTC>)}

2. Эй, чувак, я был очень рад попробовать, но, к сожалению, похоже, это не работает :(. Агрегатная функция подсчитывает все записи, а не только lastest_date.

3. извините за ваше разочарование. Я снова обновил свой ответ. Я надеюсь, что вы можете попробовать.

4. Совсем не расстроен, мой друг 🙂 большое вам спасибо за вашу помощь. Кажется, что ваш необработанный SQL делает свое дело!