Question about Django. Assistance for the implementation of registration for the tournament

Viewed 56

At the moment there are such models:

class Team(models.Model):
    name = models.CharField('Название', max_length=35, unique=True)
    tag = models.CharField('Тег', max_length=16, unique=True)
    about = models.TextField('О команду', max_length=500, null=True, blank=True)
    logo = models.ImageField('Лого', upload_to="teams_logo/", null=True)
    game = models.ForeignKey(
        Game, verbose_name='игра', on_delete=models.SET_NULL, null=True, blank=True
    )
    tournament = models.ManyToManyField('Tournaments', verbose_name='Турниры', blank=True)
    slug = models.SlugField(unique=True, blank=True, null=True)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse("team_detail", kwargs={"slug": self.slug})

    def save(self, *args, **kwargs):
        self.slug = slugify(self.name)
        super(Team, self).save(*args, **kwargs)

    class Meta:
        verbose_name = "Команда"
        verbose_name_plural = "Команды"

class Tournaments(models.Model):
    name = models.CharField('Название турнира', max_length=50)
    description = models.TextField('Описание турнира')
    prize = models.TextField('Призовой')
    game = models.ForeignKey(
        Game, verbose_name='Дисциплина', on_delete=models.CASCADE
    )
    author = models.ForeignKey(
        User, verbose_name='пользователь', on_delete=models.CASCADE, blank=True, null=True
    )
    teams = models.ManyToManyField(
        Team, verbose_name='Команда', blank=True
    )
    image = models.ImageField('Лого турнира')
    max_teams = models.PositiveSmallIntegerField('Максимальное количество команд', default=0)
    count_registration_teams = models.PositiveSmallIntegerField('Количество зарегестрированных команд', default=0)
    start_date = models.DateTimeField("Дата начала")
    start_registration_date = models.DateTimeField("Начало регистрации")
    end_registration_date = models.DateTimeField("Конец регистрации")
    slug = models.SlugField(unique=True, blank=True, null=True)
    status = models.BooleanField('Статус активности', default=False)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse("tournament_detail", kwargs={"slug": self.slug})

    def save(self, *args, **kwargs):
        self.slug = slugify(f'{self.name} - {self.game}')
        super(Tournaments, self).save(*args, **kwargs)

    def get_tournament(self):
        return self.tournamentregistration_set

    class Meta:
        verbose_name = "Турнир"
        verbose_name_plural = "Турниры"


class TournamentRegistration(models.Model):
    tournaments = models.ForeignKey(Tournaments, on_delete=models.CASCADE)
    teams = models.ForeignKey(Team, on_delete=models.CASCADE, null=True, blank=True)
    user = models.ForeignKey(
        User, verbose_name='пользователь', on_delete=models.CASCADE, blank=True, null=True
    )

I don't really know if Tournament Registration is required here at all.

And this view is present:

class TournamentsRegistration(LoginRequiredMixin, View):

    def post(self, request, pk, *args, **kwargs):
        print(f'TYT ----> {request.POST} & {request.GET}<----')
        form = TournamentsRegistrationForm(request.POST or None)
        tournaments = Tournaments.objects.get(id=pk)
        if form.is_valid():
            print("OK")
            form.save(commit=False)
            form.tournaments = tournaments
            form.teams = request.user.profile.team
            form.tournaments.count_registraion_teams += 1
            form.save()
        else:
            print('НЕВЕРНАЯ ФОРМА')
            print(form.errors)
            print(form.non_field_errors())
        return redirect(tournaments.get_absolute_url())

And forms:

class TournamentsRegistrationForm(forms.ModelForm):

    class Meta:
        model = TournamentRegistration
        fields = {'tournaments', 'teams', 'user'}

And the next HTML:

<div class="registered_teams">
  <div class="registered_teams">
    {{ tournaments.count_registration_teams }} / {{ tournaments.max_teams }}<br>
  </div>
  <div class="tournament-registration">
    <form action="{% url 'tournament_registration' tournaments.id %}" method="post">
      {% csrf_token %}
      <button type="submit">Зарегестрироваться</button>
    </form>
  </div>
</div>

The following is required, by pressing the registration button, the captain's team was added to the tournament, and the tournament was added to the team, for this purpose I used M2M communication, it is also necessary that the counter of registered teams increases by one( it is also desirable to display the name of registered teams on the page) and that the registration button is blocked for the team that is already registered for this tournament, but this is most likely I will be able to do it myself. But it seems to me that here you need to work with Tournaments and without forms.py. Perhaps someone can suggest a solution. Before that, I could only use JS to increase the team counter and block the button, but this is not added to the database in any way, but only visually displayed on the tournament page, without linking TOURNAMENT-TEAMS\TEAM-TOURNAMENT.

1 Answers

First of all: it's best practice to give your model singular names (Tournament instead of Tournaments).

Secondly, it's best practice to specify the related_name on the ManyToManyField: tournament = models.ManyToManyField('Tournament', ..., related_name='teams'). Note that this is plural.

Lastly, I wouldn't keep track of the number of teams as a separate field on Tournament. You can simply calculate it on the spot when you need it.

t = Tournament.objects.get(id=1)
print(t.teams.count())
Related