手动填充modelformset Django以进行测试

时间:2018-11-25 10:05:05

标签: python django

我遇到错误django.forms.utils.ValidationError: ['ManagementForm data is missing or has been tampered with']的问题,但这仅在测试我的代码时发生。当使用真实的POST请求呈现实际网页时,它不会引发此错误。

我有一个名为Position的模型,该表单集由其Candidate-objects组成。因此,对于一个特定职位,我可能有4个候选人。

models.py

class Candidate(models.Model):
    user = models.ForeignKey(User, related_name="candidate")
    votes = models.PositiveIntegerField(verbose_name="Antall stemmer", blank=True, default=0)


class Position(models.Model):
    # Candidates running for position
    candidates = models.ManyToManyField(Candidate, blank=True, related_name="positions")

    # Number of people voting
    number_of_voters = models.PositiveIntegerField(default=0, verbose_name="Antall stemmesedler avgitt")

forms.py

class AddPrevoteForm(forms.ModelForm):
    class Meta:
        model = Position
        fields = ['number_of_voters']


class AddPreVoteToCandidateForm(forms.ModelForm):
    class Meta:
        model = Candidate
        fields = ['votes']

    def __init__(self, *args, **kwargs):
        super(AddPreVoteToCandidateForm, self).__init__(*args, **kwargs)
        self.fields['votes'].label = self.instance.user.get_full_name()

views.py

@permission_required('elections.add_election')
@login_required
def admin_register_prevotes(request, pk):
    # Fetch position
    position = get_object_or_404(Position, pk=pk)
    # For for editing total number of people prevoting
    prevote_form = AddPrevoteForm(request.POST or None, instance=position)
    # Form for adjusting individual candidate's votes
    CandidateFormSet = modelformset_factory(
        Candidate, form=AddPreVoteToCandidateForm, extra=0
        )
    formset = CandidateFormSet(
        request.POST or None,
        queryset=position.candidates.all()
        )
    if request.method == 'POST':
        if formset.is_valid() and prevote_form.is_valid():
            for form in formset:
                # Increment both candidate and positions votes
                candidate_pk = form.instance.pk
                candidate = Candidate.objects.get(pk=candidate_pk)
                old_votes = candidate.votes
                new_votes = form.cleaned_data['votes']
                position.total_votes += (new_votes - old_votes)
                form.save()
            prevote_form.save()
            return redirect(reverse(
                'elections:admin_register_candidates',
                kwargs={'pk': position.id}
                ))
    context = {
        'prevote_form': prevote_form,
        'candidate_formset': formset,
        'position': position
    }
    return render(
        request, 'elections/admin/admin_add_prevotes.html',
        context
        )

和模板

<form method="POST">{% csrf_token %}
        {{ candidate_formset.management_form }}
        {% for candidate_form in candidate_formset %}
        <div>
            {{ candidate_form }}
        </div>
        {% endfor %}
        {{ prevote_form }}
        <div>
            <input class="button is-success" type="submit" value="Add prevotes!"></input>
        </div>
    </form>

从模板得到的formset如下所示:

<input type="hidden" name="form-TOTAL_FORMS" value="4" id="id_form-TOTAL_FORMS" /><input type="hidden" name="form-INITIAL_FORMS" value="4" id="id_form-INITIAL_FORMS" /><input type="hidden" name="form-MIN_NUM_FORMS" value="0" id="id_form-MIN_NUM_FORMS" /><input type="hidden" name="form-MAX_NUM_FORMS" value="1000" id="id_form-MAX_NUM_FORMS" />
<tr><th><label for="id_form-0-votes">Sindre Bakke:</label></th><td><input type="number" name="form-0-votes" value="3" min="0" id="id_form-0-votes" /><input type="hidden" name="form-0-id" value="1" id="id_form-0-id" /></td></tr> <tr><th><label for="id_form-1-votes">Christopher Massey:</label></th><td><input type="number" name="form-1-votes" value="2" min="0" id="id_form-1-votes" /><input type="hidden" name="form-1-id" value="2" id="id_form-1-id" /></td></tr> <tr><th><label for="id_form-2-votes">Ann Green:</label></th><td><input type="number" name="form-2-votes" value="0" min="0" id="id_form-2-votes" /><input type="hidden" name="form-2-id" value="3" id="id_form-2-id" /></td></tr> <tr><th><label for="id_form-3-votes">Michelle Murray:</label></th><td><input type="number" name="form-3-votes" value="0" min="0" id="id_form-3-votes" /><input type="hidden" name="form-3-id" value="4" id="id_form-3-id" /></td></tr>

这就是为什么我尝试了以下测试(post_data中的四个第一个来自management_form

@pytest.mark.django_db
def test_add_pre_votes_to_candidate(
        client, create_admin_user,
        create_open_election_with_position_and_candidates):
    admin = create_admin_user
    client.login(username=admin.username, password='defaultpassword')
    election = create_open_election_with_position_and_candidates
    position = election.positions.all().first()
    number_of_candidates = position.candidates.all().count()
    candidate = position.candidates.all().first()
    post_data = {
        'form-TOTAL_FORMS:': '4',
        'form-INITIAL_FORMS': '4',
        'form-MIN_NUM_FORMS': '0',
        'form-MAX_NUM_FORMS': '1000',
        'form-0-votes': '3',
        'form-0-id': 1,
        'form-1-votes': '2',
        'form-1-id': 2,
        'form-2-votes': '0',
        'form-2-id': 3,
        'form-3-votes': '0',
        'form-3-id': 4,
        'number_of_voters': '0'
    }
    client.post(
        reverse(
            'elections:admin_register_prevotes',
            kwargs={'pk': position.id}
            ),
        data=post_data
    )

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:1)

这通常是由于“管理”表单存在一些问题。 post_data中似乎有一个错字,'form-TOTAL_FORMS:'在字符串的末尾有一个额外的:

此外,在单元测试中使用隐式主键时要小心。取决于提供Candidates对象的固定装置的实现,它们在数据库中的ID可能并不总是以1,2等开头。