Skip to main content
 首页 » 编程设计

python之手动填充 modelformset Django 进行测试

2024年12月31日24dflying

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

我有一个名为 Position 的模型,表单集由其候选对象组成。所以对于一个特定的职位,我可能有 4 个候选人。

模型.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") 

表单.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() 

View .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 
    ) 

如有任何帮助,我们将不胜感激!

请您参考如下方法:

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

此外,请注意单元测试中的隐式主键。取决于提供 Candidates 的固定装置的实现对象,它们在数据库中的 ID 可能并不总是从 1,2,.. 等开始。