У меня есть тест для UpdateView, который:
- Обновление существующего объекта
- Затем попытка создать новый пустой объект в то же время
Такое поведение не происходит, когда я запускаю представление в браузере, поэтому это как-то связано с тем, как проходит тест.
- POST для 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)