Оптимизация дизайна модели на основе нескольких отношений - PullRequest
0 голосов
/ 25 мая 2019

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

В настоящее время у меня есть три модели, представляющие данные, которые я хочу собрать.Season, Challenge, Attempt.

class Season(models.Model):
    season = models.CharField(max_length=4)
    start_date = models.DateTimeField()
    end_date = models.DateTimeField()


class Challenge(models.Model):
    season = models.ForeignKey(Season, on_delete=models.CASCADE)
    name = models.CharField(max_length=255)
    start_date = models.DateTimeField()
    end_date = models.DateTimeField()

class Attempt(models.Model):
    challenger = models.ForeignKey(User, on_delete=models.CASCADE)
    challenge = models.ForeignKey(Challenge, on_delete=models.CASCADE)
    points = models.IntegerField(default=0)

Теперь я предполагаю, что следующие утверждения верны в том, что я хочу из этого извлечь.

  1. Сезон длится один год
  2. Сезон длится один месяц
  3. В сезоне может быть много испытаний
  4. В задании может быть много попыток
  5. AЗадача не может принадлежать более чем одному сезону
  6. Попытка не может принадлежать более чем одному испытанию.

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

Примерданные

Season(season='2019',
       start_date=...,  # some date object
       end_date=...,  # some date object
)

Challenge(season=1,  # represents season object above
          name='Challenge 1',
          start_date=...,  # some date object
          end_date=...,  # some date object
)

Challenge(season=1,  # represents season object above
          name='Challenge 2',
          start_date=...,  # some date object
          end_date=...  # some date object
)

Attempt(challenger=1,  # represents user object
        challenge=1,  # represents challenge 1 above
        points=5
)

Attempt(challenger=2,  # represents user object
        challenge=1,  # represents challenge 1 above
        points=10
)

Attempt(challenger=1,  # represents user object
        challenge=2,  # represents challenge 2 above
        points=5
)


Attempt(challenger=2,  # represents user object
        challenge=2,  # represents challenge 2 above
        points=10
)

Ожидаемый результат

  1. Претендент 2 - 20 баллов
  2. Претендент 1 - 10 баллов

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

Кроме того, как мне тогда получить результаты, которые я ищу, используя ORM

1 Ответ

1 голос
/ 25 мая 2019

Ваша модель хороша, не меняйте ее. Для желаемого результата попробуйте что-то вроде этого:

Attempt.objects.filter(challenge__season__season='2019').values('challenger__name').annotate(total_points=Sum('points')).order_by('-total_points')

Это берет все попытки, фильтрует их до сезона с именем «2019», затем захватывает все имена претендентов и затем агрегирует их по сумме точек попыток претендентов (что, кажется, то, что вы хотите, но вы можно использовать и Макса вместо Суммы).

Одна из проблем, связанных с этим подходом (кстати, я должен отметить этот источник: https://simpleisbetterthancomplex.com/tutorial/2016/12/06/how-to-create-group-by-queries.html), заключается в том, что если несколько претендентов имеют одно и то же имя, они будут сгруппированы вместе, чего вы, вероятно, не знаете. хочу. Поэтому вы можете сгруппировать по претендентам 'pk' и 'name'.

...