2
\$\begingroup\$

I'm trying to model a tournament with Python (Django) and I've got a function that assigns teams of the previous stage to the groups of the new one. The teams in the first stage are assigned manually.

Every Stage have OneToOneRel to the previous Stage. Team model is related to the Group through Score model, that has ForeignKeyRel with both Team and Group and store every score too.

The code down here is working but I really think he is not the best way to do it (especially the while loop).

def update_groups(request):
    if request.method == 'POST':
        stage = Stage.objects.get(id=request.POST.get('stage_id'))
        if stage.protected:
            return redirect('master_area:home')
        current_groups = []
        precedent_groups = []
        leader_boards = []
        temp = []
        rank = []

        for group in stage.precedent_stage.groups.all():
            leader_board = []
            for score in group.scores.all():
                leader_board.append(score)
            leader_board.sort(key=lambda x: x.score, reverse=True)  # sort best in group
            leader_boards.append(leader_board)

        leader_boards = [list(filter(None, i)) for i in zip_longest(*leader_boards)]  # transpose leader_boards
        for leader_board in leader_boards:
            leader_board.sort(key=lambda x: x.score, reverse=True)  # sort best firsts, seconds...
            for score in leader_board:
                temp.append(score)

        temp.sort(key=lambda x: x.group.importance, reverse=True)  # sort for the importance of the previous group
        for score in temp:
            rank.append(score.team)

        for group in stage.groups.all():
            current_groups.append(group)
        current_groups.sort(key=lambda x: x.importance, reverse=True)

        i = 0
        t = 1
        while len(rank) and len(current_groups):
            if len(current_groups[i].scores.all()) < current_groups[i].number_of_teams:
                Score.objects.get_or_create(team=rank[0], group=current_groups[i])
                rank.pop(0)
            if i+t < 0 or i+t >= len(current_groups) or current_groups[i+t].importance is not current_groups[i].importance:
                t = -1 if t == 1 else 1
                if len(current_groups[i].scores.all()) == current_groups[i].number_of_teams:
                    rem = current_groups[i].importance
                    current_groups.pop(i)
                    if t == 1:
                        i -= 1
                    elif i < len(current_groups) and rem is not current_groups[i].importance:
                        t = 1
                    elif len(current_groups) == 1:
                        i=0
            else:
                i += t
                if len(current_groups[i].scores.all()) >= current_groups[i].number_of_teams:
                    current_groups.pop(i)
                    if t == 1:
                        i -= 1

        return redirect('master_area:home')

Here my models:

class Team(models.Model):
    tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE, null=True, related_name='teams')
    name = models.CharField(max_length=24)
    short_name = models.CharField(max_length=12, blank=True)
    city = models.CharField(max_length=36, blank=True)
    slug = models.SlugField(blank=True)

class Tournament(models.Model):
    year = models.CharField(max_length=99)
    title = models.CharField(max_length=99, blank=True)
    slug = models.SlugField(blank=True)
    active = models.BooleanField(default=False)

class Stage(models.Model):  # Fase
    name = models.CharField(max_length=16, blank=True)
    tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE, related_name='stages')
    precedent_stage = models.OneToOneField('self', on_delete=models.SET_NULL, blank=True, null=True, related_name='next_stage')
    protected = models.BooleanField(default=False)

class Group(models.Model):  # Girone
    name = models.CharField(max_length=16, blank=True)
    FORMAT_TYPES = (('Round-Robin', "All'italiana"), ('Elimination', 'Ad eliminazione'))
    stage = models.ForeignKey(Stage, on_delete=models.CASCADE, related_name='groups')
    format = models.CharField(max_length=32, choices=FORMAT_TYPES, default='Round-Robin')
    number_of_teams = models.IntegerField(validators=[MinValueValidator(0)], default=0)
    importance = models.IntegerField(validators=[MinValueValidator(0)], default=0)

class Score(models.Model):  # Punteggio
    team = models.ForeignKey(Team, on_delete=models.CASCADE, related_name='scores')
    group = models.ForeignKey(Group, on_delete=models.CASCADE, null=True, related_name='scores')
    score = models.IntegerField(validators=[MinValueValidator(0)], blank=True, null=True, default=0)
    games_played = models.IntegerField(validators=[MinValueValidator(0)], blank=True, null=True, default=0)
    wins = models.IntegerField(validators=[MinValueValidator(0)], blank=True, null=True, default=0)
    losses = models.IntegerField(validators=[MinValueValidator(0)], blank=True, null=True, default=0)
    points_made = models.IntegerField(validators=[MinValueValidator(0)], blank=True, null=True, default=0)
    points_conceded = models.IntegerField(validators=[MinValueValidator(0)], blank=True, null=True, default=0)
    goals_made = models.IntegerField(validators=[MinValueValidator(0)], blank=True, null=True, default=0)
    goals_conceded = models.IntegerField(validators=[MinValueValidator(0)], blank=True, null=True, default=0)
\$\endgroup\$
  • 2
    \$\begingroup\$ @MathiasEttinger Thanks, it was temp.sort(.... \$\endgroup\$ – Lorenzo Fiamingo Jan 10 at 23:43
  • \$\begingroup\$ Without having an understanding of how new groups are generated, it's honestly very difficult to review this code. I took a shot at it and gave up once I realized I was going to need to draw a few diagrams for myself. \$\endgroup\$ – Kevin Brown Feb 10 at 22:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.