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

#python #django #django-models #django-queryset #django-orm

Вопрос:

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

У меня есть три основные модели: Команда, Подразделение и Конференция. Вот их урезанная версия, чтобы проиллюстрировать их отношения друг к другу.

 class Conference(models.Model):
    name = models.CharField(max_length=200)

class Division(models.Model):
    name = models.CharField(max_length=200)
    conference = models.ForeignKey(
        Conference, on_delete=models.CASCADE,
        related_name='divisions'
    )

class Team(models.Model):
    division = models.ForeignKey(
        Division, on_delete=models.CASCADE,
        related_name='teams',
    )
 

Я создаю рейтинги для каждой из команд в их соответствующих подразделениях и конференциях на основе их командного рейтинга в начале каждой недели (победы, поражения и т.д.). Рейтинги будут сохранены в экземпляре TeamRanking (их пронумерованный ранг в их дивизионе 1-4, конференции 1-16 и в масштабах лиги 1-32), который имеет единственную связь с командой (по одному в каждой команде в неделю).

Урезанная версия вышеперечисленных моделей также:

 class TeamStanding(models.Model):
    team = models.ForeignKey(
        Team, on_delete=models.CASCADE,
        related_name='team_standings',
    )
    # All the standing data fields

class TeamRanking(models.Model):
    standing = models.OneToOneField(
        TeamStanding, related_name='ranking',
        on_delete=models.CASCADE,
    )
    # All the rankings fields
 

Вот как в настоящее время рассчитывается рейтинг дивизионов:

 division_rank_qs = TeamStanding.objects.filter(
        team__division__exact=division
    ).annotate(
        rank=Window(
            expression=Rank(),
            order_by=[
                F('wins').desc(), F('losses'),
                F('points_for').desc(),
                F('points_against')
            ],
        )
    )
 

Then to access the ranks:

 for ranked_div_standing in division_rank_qs:
    rank = ranked_div_standing.rank
    # Create TeamRanking instance
 

Now this works fine for the basic division rankings calculations. The issue I’m running into is when calculating conference rankings, as these somewhat depend on the division rankings. There are 4 divisions per conference and 4 teams per division.

Each team with Rank 1 in their division needs to be in the top 4 of the conference rankings no matter what, but ranked 1-4 based on the ordering criteria taking into account JUST those 3 other division leading teams. Then the rest of the 13 teams in the conference will use that same ordering criteria but EXCLUDING the top 4 teams that were ordered separately. So two completely separating orderings based on a cutoff between rank 4 and 5.

This is what I was able to come up with so far. I’m using the TeamRanking already stored for the division in the ordering, but the problem is I can’t limit it to just look for the #1 rankings and stop using that after the first 4 conference leaders are ordered.

 conference_rank_qs = TeamStanding.objects.filter(
        team__division__conference__exact=conference
    ).annotate(
        rank=Window(
            expression=Rank(),
            order_by=[
                F('ranking__division_ranking'),
                F('wins').desc(), F('losses'),
                F('points_for').desc(),
                F('points_against')
            ],
        )
    )
 

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

Если вам нужна какая-либо дополнительная информация, пожалуйста, дайте мне знать в комментариях. Спасибо.