在Django中使用ModelFormSet测试发布请求

时间:2016-07-27 17:52:40

标签: python django django-forms django-templates

我是django和测试的新手,所以我不确定这个问题是否有更简单的解决方案。

我创建了一个评估应用程序,其中包含用户可以编辑,提交和更新的量规。每个量规具有预设数量的行模型,这些行模型通过外键关系连接到量规模型。用户应该能够更新多个行模型中的多个row_choice字段,并将row_choice字段发布到数据库。

为了在模板中描绘它,我决定使用ModelFormSet并遍历rubric.html中的ModelFormSet。这工作正常,但每当我尝试使用TestCase测试此布局时,我收到错误 [' ManagementForm数据丢失或已经被篡改过了']。我理解这个错误,因为测试没有使用rubric.html(其中找到ManagementForm)将视图请求传递给视图,但是应用程序在浏览器中工作,因为django模板将ManagementForm呈现为html,在视图中没有问题。

您可以使用TestCase在django中测试ModelFormSet,还是 使用LiveServerTestCase和Selenium?有没有办法让示例测试通过并仍然测试一个post请求(使用ModelFormSet时)?非常感谢任何帮助。

forms.py

class RowForm(ModelForm):
    class Meta:
        model = Row
        fields = ['row_choice']

class RubricForm(ModelForm):
    class Meta:
        model = Rubric
        fields = ['name']

RowFormSet = modelformset_factory(Row, fields=('row_choice',), extra=0) 

失败测试的一个例子:

def test_rubric_page_can_take_post_request(self):
    self.add_two_classes_to_semester_add_two_students_to_class_add_one_row()
    request = HttpRequest()
    request.method = "POST"
    response = rubric_page(request, "EG5000", "12345678")

    self.assertEqual(response.status_code, 302)

和追溯:

Traceback (most recent call last):
  File "C:\python33\assessmenttoolstaging\source\rubricapp\tests\tests.py", line 240, in test_rubric_page_can_take_post_request
    response = rubric_page(request, "EG5000", "12345678")
  File "C:\python33\assessmenttoolstaging\source\rubricapp\views.py", line 52, in rubric_page
    RowFormSetWeb.clean()
  File "C:\Python33\lib\site-packages\django\forms\models.py", line 645, in clean
    self.validate_unique()
  File "C:\Python33\lib\site-packages\django\forms\models.py", line 651, in validate_unique
    forms_to_delete = self.deleted_forms
  File "C:\Python33\lib\site-packages\django\forms\formsets.py", line 205, in deleted_forms
    if not self.is_valid() or not self.can_delete:
  File "C:\Python33\lib\site-packages\django\forms\formsets.py", line 304, in is_valid
    self.errors
  File "C:\Python33\lib\site-packages\django\forms\formsets.py", line 278, in errors
    self.full_clean()
  File "C:\Python33\lib\site-packages\django\forms\formsets.py", line 325, in full_clean
    for i in range(0, self.total_form_count()):
  File "C:\Python33\lib\site-packages\django\forms\formsets.py", line 115, in total_form_count
    return min(self.management_form.cleaned_data[TOTAL_FORM_COUNT], self.absolute_max)
  File "C:\Python33\lib\site-packages\django\forms\formsets.py", line 97, in management_form
    code='missing_management_form',
django.core.exceptions.ValidationError: ['ManagementForm data is missing or has been tampered with']

rubric_page视图

def rubric_page(request, edclass, studentname):
    edClassSpaceAdded = re.sub('([A-Z]+)', r'\1 ', edclass)
    enrollmentObj = Enrollment.objects.get(edclass__name=edClassSpaceAdded, student__lnumber=studentname)
    rubricForClass = enrollmentObj.keyrubric.get()
    rows = Row.objects.filter(rubric=rubricForClass)
    student = Student.objects.get(lnumber=studentname)
    if request.method == 'POST':
        #TestCase cannot test this section of the view
        RowFormSetWeb = RowFormSet(request.POST)
        RowFormSetWeb.clean()
        if RowFormSetWeb.is_valid():
            savedFormset = RowFormSetWeb.save(commit=False)
            for i in savedFormset:
                i.rubric = rubricForClass 
            RowFormSetWeb.save()
            return redirect('/'+ edclass + '/')
        else:
            return render(request, 'rubric.html', {'studentlnumber': student.lnumber,'studentname': student.lastname + ", " + student.firstname, 'RowFormSetWeb':RowFormSetWeb, 'rows':rows, 'edclass':edclass})
    else:
        RowFormSetWeb = RowFormSet(queryset=Row.objects.filter(rubric=rubricForClass))
        return render(request, 'rubric.html', {'studentlnumber': student.lnumber,'studentname': student.lastname + ", " + student.firstname, 'RowFormSetWeb':RowFormSetWeb, 'rows':rows, 'edclass':edclass})

rubric.html的表单部分

    <h3 id="rubricheader">TODO Pull model into view</h3>
    <form method="post" action= {% url 'rubricpage' edclass=edclass studentname=studentlnumber %}>

    <table border="1">
<!-- TODO fix this so that it pulls from forms.py -->
        <tr>
            <th></th>
            <th>Excellent</th>
            <th>Proficient</th>
            <th>Sub-par</th>
            <th>Abysmal</th>
        </tr>
            {{ RowFormSetWeb.management_form }}
            {% for form in RowFormSetWeb %}
                {{ form.id }}
            <tr>
                <td>{{ form.row_choice }}</td><td>{{ form.excellenttext }}</td><td>{{ form.proficienttext }}</td><td>{{ form.satisfactorytext }}<td>{{ form.unsatisfactorytext }}</td>
            </tr>
            {{ RowFormSetWeb.errors }}
            {% endfor %}

    </table>
    <input name="submitbutton" type="submit" name="submit" value="Submit" id="rubricsubmit">
{% csrf_token %}
</form>
{% endblock %}

models.py

来自django.db导入模型

class Student(models.Model):
    firstname = models.TextField(default="")    
    lastname = models.TextField(default="")
    lnumber = models.TextField(default="")

    def __str__(self):
        return self.lnumber
    #TODO add models

class EdClasses(models.Model):
    name = models.TextField(default='')
    students = models.ManyToManyField(Student, through="Enrollment")
    def __str__(self):
        return self.name

class Semester(models.Model):
    text = models.TextField(default='201530')
    classes = models.ManyToManyField(EdClasses) 
    def __str__(self):
        return self.text


class Rubric(models.Model):
    name = models.TextField(default="Basic Rubric")

    def __str__(self):
        return self.name


class Row(models.Model):
    CHOICES = (
    (None, 'Your string for display'),
    ('1','Excellent'),
    ('2','Proficient'),
    ('3','Awful'),
    ('4','The worst ever'),
    )
    rubric = models.ForeignKey(Rubric)
    row_choice = models.CharField(max_length=20,choices=CHOICES, default="None", blank=True)
    excellenttext = models.TextField(default="")
    proficienttext = models.TextField(default="")
    satisfactorytext = models.TextField(default="")
    unsatisfactorytext = models.TextField(default="")

    def __str__(self):
        return self.row_choice


class Enrollment(models.Model):
    student = models.ForeignKey(Student)
    edclass = models.ForeignKey(EdClasses)
    grade = models.TextField(default='') 
    keyrubric = models.ManyToManyField(Rubric)

如何在浏览器中呈现表单:

<form action="/201530/EG5000/21743148/" method="post">
<table border="1">
<!-- TODO fix this so that it pulls from forms.py -->
<tr>
<th></th>
<th>Excellent</th>
<th>Proficient</th>
<th>Sub-par</th>
<th>Abysmal</th>
</tr>
<input id="id_form-TOTAL_FORMS" name="form-TOTAL_FORMS" type="hidden" value="2"/><input id="id_form-INITIAL_FORMS" name="form-INITIAL_FORMS" type="hidden" value="2"/><input id="id_form-MIN_NUM_FORMS" name="form-MIN_NUM_FORMS" type="hidden" value="0"/><input id="id_form-MAX_NUM_FORMS" name="form-MAX_NUM_FORMS" type="hidden" value="1000"/>
<input id="id_form-0-id" name="form-0-id" type="hidden" value="3"/>
<tr>
<td><select id="id_form-0-row_choice" name="form-0-row_choice">
<option value="">Your string for display</option>
<option value="1">Excellent</option>
<option value="2">Proficient</option>
<option value="3">Awful</option>
<option value="4">The worst ever</option>
</select></td>
<td>THE BEST!</td>
<td>THE SECOND BEST!</td>
<td>THE THIRD BEST!</td>
<td>YOURE LAST</td>
</tr>
                                        []

                                                <input id="id_form-1-id" name="form-1-id" type="hidden" value="4"/>
<tr>
<td><select id="id_form-1-row_choice" name="form-1-row_choice">
<option value="">Your string for display</option>
<option value="1">Excellent</option>
<option value="2">Proficient</option>
<option value="3">Awful</option>
<option value="4">The worst ever</option>
</select></td>
<td>THE GREATEST!</td>
<td>THE SECOND BEST!</td>
<td>THE THIRD BEST!</td>
<td>YOURE LAST</td>
</tr>
                                        []



                        </table>
<input id="rubricsubmit" name="submit" type="submit" value="Submit">
<input name="csrfmiddlewaretoken" type="hidden" value="0OeU2n0v8ooXHBxdUfi26xxqMIdrA50L"/>
</input></form>

1 个答案:

答案 0 :(得分:1)

我过去使用的一种方法,虽然不是特别好的方法,但是使用客户端获取渲染的表单,然后使用类似BeautifulSoup的东西从中解析出所有表单数据并在必要时更新回帖。这样,您将获得所有隐藏和预填充的字段,因此您可以确保您的测试行为与用户的行为相同。