【发布时间】:2019-10-21 00:23:15
【问题描述】:
我对 UpdateView 进行了测试:
- 更新现有对象
- 然后尝试同时创建一个新的空白对象
当我在浏览器中运行视图时不会发生这种行为,因此它与测试的运行方式有关。
- 发布到更新 URL
- 请求通过 UpdateView 运行
- Form_valid() 运行并命中
instance.save() - 然后某些东西导致在保存原始对象后立即创建第二个对象
有什么想法吗?
测试
class TestReviewUpdateView(TestCase):
def setUp(self):
self.review = ReviewFactory()
self.submission = self.review.submission
self.factory = RequestFactory()
self.kwargs = {'submission_pk': self.submission.pk}
def test_form_valid_with_object(self):
self.request = self.factory.post(reverse(
'submissions:review_update', kwargs=self.kwargs))
# Create user
self.request.user = StaffFactory()
view = views.ReviewUpdateView()
view.request = self.request
view.object = self.review
kwargs = {
'scores': self.review.get_list_of_scores()
}
form = forms.ReviewForm(**kwargs)
form.cleaned_data = {'axe_0': '4', 'axe_1': '4', 'axe_2': '4'}
response = view.form_valid(form)
assert response.status_code == 302
观点
class ReviewUpdateView(
BaseReviewForm,
UpdateView
):
""" A view for updating reviews. """
def dispatch(self, request, *args, **kwargs):
self.submission = self.get_submission()
self.conference = self.submission.conference
return super().dispatch(request, *args, **kwargs)
def get_submission(self):
return Submission.upcoming_objects.get_queryset(self.request.user).get(
pk=self.kwargs['submission_pk'])
def get_object(self):
return self.model.objects.get(
submission=self.submission,
user=self.request.user)
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs.update({
'scores': self.object.get_list_of_scores(),
})
return kwargs
def save_scores(self, form, instance):
for field in form.cleaned_data:
# The score fields will be numbers:
if "axe_" in field:
form_field = form.fields[field]
# Save the field's label as the key and score as value
instance.scores[form_field.label] = form.cleaned_data[field]
return instance
def form_valid(self, form):
instance = self.get_object()
instance = self.save_scores(form, instance)
instance.save()
return super().form_valid(form)
表格
class ReviewForm(forms.ModelForm):
""" Form for new reviews of submissions """
class Meta:
model = Review
fields = []
def __init__(self, *args, **kwargs):
review_fields = kwargs.pop("review_fields")
scores = kwargs.pop("scores")
super().__init__(*args, **kwargs)
if review_fields:
for i in review_fields:
self.fields["axe_%s" % i] = forms.ChoiceField(
choices=NUMBER_CHOICES,
label=review_fields[i],
widget=forms.RadioSelect)
if scores:
self.fields["axe_%s" % i].initial = scores[int(i)]
self.helper = FormHelper()
self.helper.layout = Layout()
for i in review_fields:
self.helper.layout.fields.append(
InlineRadios("axe_%s" % i)
)
self.helper.layout.fields.append(
ButtonHolder(
Submit('submit', 'Submit', css_class='btn btn-primary')
)
模型
class Review(TimeStampedModel):
""" Review is a model for collecting answers from reviewers """
id = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
editable=False,
)
user = models.ForeignKey(
get_user_model(),
null=False,
on_delete=models.PROTECT)
submission = models.ForeignKey(
Submission,
null=False,
on_delete=models.CASCADE
)
scores = JSONField(null=True, blank=True)
avg_score = models.DecimalField(max_digits=3, decimal_places=2, default=0)
class Meta:
unique_together = ("user", "submission")
ordering = ['-avg_score', '-created']
def save(self, *args, **kwargs):
self.avg_score = self.calc_avg_score()
import pdb; pdb.set_trace()
# save() is called twice and when it runs a second time, it errors because no values are set
super().save(*args, **kwargs)
self.submission.save()
回答
@dirkgroten 为我指明了正确的方向。代码解决方案如下-
def test_form_valid_with_object(self):
user = User.objects.create_superuser('foo', 'myemail@test.com', 'bar')
self.review.user = user
self.review.save()
self.submission.conference.reviewers.add(user)
self.client.login(username='foo', password='bar')
response = self.client.post(
reverse('submissions:review_update', kwargs=self.kwargs),
data={'axe_0': '4', 'axe_1': '4', 'axe_2': '4'})
self.assertEqual(302, response.status_code)
【问题讨论】:
-
这不是您应该测试视图的方式:您应该只提交对该视图的请求 (
response = self.factory.post(url, data={...})) 并对响应做出断言。不要尝试自己制作视图对象。 -
谢谢,这也是我需要的反馈。
标签: django django-forms django-views django-testing