Это хороший способ обработки нескольких наборов форм в одном представлении? - PullRequest
0 голосов
/ 21 мая 2019

Сначала я использую Python 3.7.3 и Django 2.2

Я столкнулся с проблемой обработки нескольких наборов форм в одном представлении. На мой взгляд, я создаю свои наборы форм в цикле for (см. Ниже), а затем добавляю их в список. В моем шаблоне я делаю цикл for в этом списке и отображаю набор форм в шаблоне. Я думаю, что то, что я сделал, работает хорошо, но что-то не так происходит, когда набор форм недопустим (потому что я тоже сделал некоторую проверку). Когда набор форм недопустим (поскольку значения не принимаются), другие наборы форм также инициализируются с этими значениями. Почему?

models.py

class Set(models.Model):
    timeSet     = models.DecimalField(max_digits=5, decimal_places=2, blank=True, null=True)
    scoreTeam1  = models.IntegerField(null=True)
    scoreTeam2  = models.IntegerField(null=True)
    match       = models.ForeignKey(Match, default=None, on_delete=models.CASCADE)

class Match(models.Model):
    isFinished  = models.BooleanField(default=False)
    team1Win    = models.BooleanField(default=False)
    team2Win    = models.BooleanField(default=False)
    phase       = models.ForeignKey(Phase, default=None, on_delete=models.CASCADE)
    teams       = models.ManyToManyField(Team, default=None, blank=True)

tournament_manage_phase_matches.html

{% for match in matches %}
                    {% if match.teams.first.pool == pool %}
                        <div class="col-lg-12">
                            {% if match.isFinished == False %}
                                <div class="btn-group dropright">
                                    <button type="button" class="btn btn-secondary">
                                        Field number : {{ pool.field.numField }} | {{ match.teams.first.name }} VS {{ match.teams.last.name }}
                                    </button>
                                    <button type="button" class="btn btn-secondary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                                        <span class="sr-only">Toggle Dropright</span>
                                    </button>
                                    <div class="dropdown-menu">
                                        {% for formset_set in list_formset_set %}
                                            {% if formset_set.match == match %}
                                                <form class="px-4 py-3" method="post">
                                                {% csrf_token %}
                                                    {{ formset_set|crispy }}
                                                    {{ formset_set.management_form }}
                                                    <button type="submit" class="btn btn-primary" value="{{ match.pk }}" name="match_pk">Save score</button>
                                                </form>
                                            {% endif %}
                                        {% endfor %}
                                    </div>
                                </div>
                            {% else %}
                                {% if match.team1Win == False and match.team2Win == False %}
                                    <label>{{ match.teams.first.name }} VS {{ match.teams.last.name }} : Match nul</label>
                                {% else %}
                                    {% if match.team1Win == True and match.team2Win == False %}
                                        <label>{{ match.teams.first.name }} VS {{ match.teams.last.name }} : Victory {{ match.teams.first.name }}</label>
                                    {% endif %}
                                    {% if match.team1Win == False and match.team2Win == True %}
                                        <label>{{ match.teams.first.name }} VS {{ match.teams.last.name }} : Victory {{ match.teams.last.name }}</label>
                                    {% endif %}
                                {% endif %}
                            {% endif %}
                        </div>
                    {% endif %}
                {% endfor %}

Итак, напомним, что когда я отправляю набор форм, если он недействителен, все остальные наборы форм становятся похожими на набор форм, который я просто отправляю, и я не понимаю, почему. Если вы видите что-то не так в том, что я сделал, пожалуйста, сообщите мне тоже

Редактировать:
views.py

...
#creation of forms
    list_formset_set = []
    for match in matches:
        if match.isFinished == False:
            formset_set = MatchSetFormset(request.POST or None, instance=match, prefix="form-" + str(match.pk) + "-match")
            formset_set.match = match
            list_formset_set.append(formset_set)

    for formset_set in list_formset_set:
        id_match_submit = request.POST.get("match_pk")
        str_id_match_formet_set = str(formset_set.match.pk)
        if id_match_submit == str_id_match_formet_set:
            if formset_set.is_valid():
                formset_set.save()
                nb_set_winner_t1 = 0
                nb_set_winner_t2 = 0
                for set_match in formset_set:
                    if set_match.cleaned_data.get('scoreTeam1') == set_match.cleaned_data.get('scoreTeam2'):
                        nb_set_winner_t1 += 0
                        nb_set_winner_t2 -= 0
                    else:
                        if set_match.cleaned_data.get('scoreTeam1') > set_match.cleaned_data.get('scoreTeam2'):
                            nb_set_winner_t1 += 1
                            nb_set_winner_t2 -= 1
                        else:
                            nb_set_winner_t1 -= 1
                            nb_set_winner_t2 += 1   

                match = formset_set.cleaned_data[0].get('match')
                team1 = formset_set.cleaned_data[0].get('match').teams.first()
                team2 = formset_set.cleaned_data[0].get('match').teams.last()
                if nb_set_winner_t1 == nb_set_winner_t2:
                    team1.totalpoints += sport.nbPointPerDraw
                    team2.totalpoints += sport.nbPointPerDraw
                    team1.save()
                    team2.save()
                    match.isFinished = True
                    match.save()
                else:
                    if nb_set_winner_t1 > nb_set_winner_t2:
                        team1.totalpoints += sport.nbPointPerVictory
                        team1.nbVictory += 1
                        team2.totalpoints += sport.nbPointPerDefeat
                        team2.nbDefeat += 1
                        team1.save()
                        team2.save()
                        match.team1Win = True
                        match.isFinished = True
                        match.save()
                    else:
                        team1.totalpoints += sport.nbPointPerDefeat
                        team1.nbDefeat += 1
                        team2.totalpoints += sport.nbPointPerVictory
                        team2.nbVictory += 1
                        team1.save()
                        team2.save()
                        match.team2Win = True
                        match.isFinished = True
                        match.save()
                teams = Team.objects.filter(pool__in=pools).order_by('-totalpoints') #"-" means descending
                for index, team in enumerate(teams):
                    team.position = index + 1
                return redirect('matches_phase_manage_tournament', id=id, id_phase=id_phase)
            else:
                # reload formsets
                print("invalid")

Окружающая среда:
Способ запроса: POST
URL запроса: http://127.0.0.1:8000/tournament/admin-1/manage-phase/30-matches/
Версия Django: 2.2
Версия Python: 3.7.3
Установленные приложения:
[ 'Django.contrib.admin',
'Django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'Users.apps.UsersConfig',
'crispy_forms',
'категория',
'подставляется',
'фаза',
'пулы',
'правила',
'множество',
'спорт',
'команды',
'турниры',
'страницы',
'гимназии',
'поля']
Установленное промежуточное ПО:
[ 'Django.middleware.security.SecurityMiddleware',
'Django.contrib.sessions.middleware.SessionMiddleware',
'Django.middleware.common.CommonMiddleware',
'Django.middleware.csrf.CsrfViewMiddleware',
'Django.contrib.auth.middleware.AuthenticationMiddleware',
'Django.contrib.messages.middleware.MessageMiddleware',
'Django.middleware.clickjacking.XFrameOptionsMiddleware']
Traceback:
Файл "C: \ Users \ 33643 \ Documents \ Projets Django \ TournamentManagerApp \ lib \ site-packages \ django \ core \ handlers \ exception.py" во внутреннем
34. response = get_response (запрос)

Файл "C: \ Users \ 33643 \ Documents \ Projets Django \ TournamentManagerApp \ lib \ site-packages \ django \ core \ handlers \ base.py" в _get_response
115. response = self.process_exception_by_middleware (e, запрос)

Файл "C: \ Users \ 33643 \ Documents \ Projets Django \ TournamentManagerApp \ lib \ site-packages \ django \ core \ handlers \ base.py" в _get_response
113. response = wrapped_callback (запрос, * callback_args, ** callback_kwargs)

Файл "C: \ Users \ 33643 \ Documents \ Projets Django \ TournamentManagerApp \ src \ pages \ views.py" в match_phase_view
370. печать (форма)

Файл "C: \ Users \ 33643 \ Documents \ Projets Django \ TournamentManagerApp \ lib \ site-packages \ django \ utils \ html.py" в
388. klass. str = лямбда-сам: mark_safe (klass_str (self))

Файл "C: \ Users \ 33643 \ Documents \ Projets Django \ TournamentManagerApp \ lib \ site-packages \ django \ forms \ formsets.py" в str
64. вернуть self.as_table ()

Файл "C: \ Users \ 33643 \ Documents \ Projets Django \ TournamentManagerApp \ lib \ site-packages \ django \ forms \ formsets.py" в as_table
404. forms = '' .join (form.as_table () для формы в себе)

Файл "C: \ Users \ 33643 \ Documents \ Projets Django \ TournamentManagerApp \ lib \ site-packages \ django \ forms \ formsets.py" в iter
68. вернуть iter (self.forms)

Файл "C: \ Users \ 33643 \ Documents \ Projets Django \ TournamentManagerApp \ lib \ site-packages \ django \ utils \ functions.py" в get
80. res = экземпляр. dict [self.name] = self.func (экземпляр)

Файл "C: \ Users \ 33643 \ Documents \ Projets Django \ TournamentManagerApp \ lib \ site-packages \ django \ forms \ formsets.py "в формах
136. для i в диапазоне (self.total_form_count ())]

Файл" C: \ Users \ 33643 \ Documents \ Projets Django \ "TournamentManagerApp \ lib \ site-packages \ django \ forms \ formsets.py "в total_form_count
110. возврат мин. (Self.management_form.cleaned_data [TOTAL_FORM_COUNT], self.absolute_max)

файл" C: \ "Пользователи \ 33643 \ Documents \ Projets Django \ TournamentManagerApp \ lib \ site-packages \ django \ utils \ functions.py "в get
80. res = instance. dict [self.name] = self.func (instance)

Файл "C: \ Users \ 33643 \ Documents \ Projets Django \ TournamentManagerApp \ lib \ site-packages \ django \ forms \ formsets.py" в management_form
92. code = 'missing_management_form',

Тип исключения: ошибка ValidationError в / турнире / admin-1 / фазы управления / 30-матчах /
ИсключениеЗначение: ['Данные ManagementForm отсутствуют или подделаны']

1 Ответ

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

Проверьте исходный код HTML, и вы увидите, что все ваши наборы форм имеют одинаковый префикс.Например, у вас будет несколько полей ввода с атрибутом name, установленным в form-0-match, что соответствует полю match первой формы (индекс 0) в наборе форм.

Когдаиспользуя несколько наборов форм в представлении (как описано здесь ), необходимо убедиться, что каждый набор форм имеет свой префикс .

Вы можете установить префикс, передав аргумент prefix инициализатору набора форм, например:

formset_set = MatchSetFormset(request.POST or None, instance=match, prefix=f"form{match.pk}")
...