问题
I am trying to test that a model form is valid.
In the test function, I create the two models that feature in my custom form. I add the data to fill the form's required fields.
When I run the tests and call is_valid()
on the form, the test fails and the form gives the error that the option that I have added is not one of the available choices
. This suggests to me that I have incorrectly added the Option
instance to the form or to the test. I am unsure how.
How can I make the model form valid for the test?
tests.py
def test_valid_data(self):
question_1 = Question(
question_text='What is the width of the telephone?',
date_published=timezone.now(),
collection=Collection.objects.create()
)
question_1.save()
option_1 = question_1.options.create(
question=question_1,
option_text='Five centimetres'
)
option_1.save()
data = {'question_text': question_1.question_text, 'selected_option': option_1.option_text,}
form = QuestionForm(data=data)
print(form)
self.assertTrue(form.is_valid())
forms.py
class QuestionForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(QuestionForm, self).__init__(*args, **kwargs)
self.fields['selected_option'] = forms.ChoiceField(
choices=[
(f'{option.pk}', f'{option}')
for option in Option.objects.filter(question_id=self.instance.pk)
],
widget=RadioSelect,
required=True,
error_messages={
'required': 'The question form lacks a selected_option'
}
)
class Meta:
model = Question
fields = ('question_text',)
labels = {
'question_text': ''
}
widgets = {
'question_text': forms.Textarea(attrs={'cols': '40', 'rows': '2'})
}
models.py
class Question(models.Model):
question_text = models.CharField(max_length=400)
collection = models.ForeignKey(Collection, on_delete=models.PROTECT, default=None)
date_published = models.DateTimeField('date published')
def __str__(self) -> str:
return self.question_text
class Option(models.Model):
option_text = models.CharField(max_length=400)
question = models.ForeignKey(Question, on_delete=models.CASCADE)
class Meta:
default_related_name = 'options'
def __str__(self) -> str:
return self.option_text
Expected: is_valid()
-> True
Actual:is_valid()
-> False
回答1:
The issue is caused by the way that you have defined choices in QuestionForm.__init__
:
choices=[
(f'{option.pk}', f'{option}')
for option in Option.objects.filter(question_id=self.instance.pk)
],
You have created choices
based on the pk
of the Question
instance related with the QuestionForm
you initiate.
In your test (and also in the admin), the form
is not bound to any instance of Question
when you initiate the form by entering
form = QuestionForm(data=data)
.
Consequently, the query Option.objects.filter(question_id=self.instance.pk)
returns None
because self.instance.pk
is None
.
Therefore, you receive the error before saving the QuestionForm
because choices = []
The query would return results if you pressed the "Save" button or if you do a form.save()
.
来源:https://stackoverflow.com/questions/56061676/how-can-i-write-a-unittest-to-check-that-a-django-model-form-is-valid