我正在为ModelForm开发单元测试,我发现当我传入一个在为字段定义的查询集中无法选择的值时,表单上的ModelChoiceField没有引发invalid_choice ValidationError。
我认为原因是没有首先调用ModelChoiceField的to_python(),因为文档说https://docs.djangoproject.com/en/1.4/ref/forms/validation/#form-and-field-validation或to_python()在调用表单和模型的干净方法之前没有捕获DoesNotExist异常,后者导致未处理的例外情况包括在内:
# Test Results
E
======================================================================
ERROR: test_clean (tickets.tests.PaymentFormTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/anand/Ubuntu One/paytickets/park_db/tickets/tests.py", line 187, in test_clean
self.assertFalse(form.is_valid())
File "/usr/local/lib/python2.7/dist-packages/django/forms/forms.py", line 124, in is_valid
return self.is_bound and not bool(self.errors)
File "/usr/local/lib/python2.7/dist-packages/django/forms/forms.py", line 115, in _get_errors
self.full_clean()
File "/usr/local/lib/python2.7/dist-packages/django/forms/forms.py", line 272, in full_clean
self._post_clean()
File "/usr/local/lib/python2.7/dist-packages/django/forms/models.py", line 332, in _post_clean
self.instance.clean()
File "/home/anand/Ubuntu One/paytickets/park_db/tickets/models.py", line 133, in clean
fine = self.ticket.fine_amount
File "/usr/local/lib/python2.7/dist-packages/django/db/models/fields/related.py", line 343, in __get__
raise self.field.rel.to.DoesNotExist
DoesNotExist
现在,当我注释掉我的模型的clean方法时,表单的行为与预期的一样,并且引发了invalid_choice错误;这告诉我在to_python方法之前调用了我的模型的clean方法。
请帮助我了解这里发生了什么。我怎样才能使这个测试工作?我正在使用Django 1.4.3。我的代码如下:
# models.py
class Payment(TimeStampedModel): # TimeStampedModel is an abstract base class
user = models.ForeignKey(User, editable=False)
ticket = models.ForeignKey('Ticket', to_field='number')
payment_amount = models.DecimalField(max_digits=7, decimal_places=2)
def clean(self):
fine = self.ticket.fine_amount
payment_sum = self.ticket.sum_payments()
remaining = fine - payment_sum
if self.payment_amount < 1:
msg = 'The minimum payment is $1.'
raise ValidationError(msg)
elif remaining == 0:
msg = 'That ticket has already been fully paid.'
raise ValidationError(msg)
elif remaining < self.payment_amount:
msg = ('You cannot pay more than the oustanding fine: $%0.2f' %
remaining)
raise ValidationError(msg)
def __unicode__(self):
return u'%s; %s; %s' % (self.created, self.ticket, self.payment_amount)
# forms.py
class PaymentForm(forms.ModelForm):
class Meta:
model = Payment
def __init__(self, user=None, *args, **kwargs):
super(PaymentForm, self).__init__(*args, **kwargs)
# passing in user and performing query for ModelChoiceField options
self._user = user
vehicles = self._user.vehicle_set.all().prefetch_related('ticket_set')
ticket_list= []
for i in vehicles:
for j in i.ticket_set.all():
ticket_list.append(j.pk)
self.ticket_queryset = Ticket.objects.filter(pk__in=ticket_list)
self.fields['ticket'].queryset = self.ticket_queryset
def save(self, commit=True):
instance = super(PaymentForm, self).save(commit=False)
instance.user = self._user
if commit:
instance.save()
return instance
# tests.py
class PaymentFormTests(TestCase):
fixtures = ['test_users.json', 'tickets_app.json']
def test_clean(self):
user = User.objects.get(username="test_external_active")
form_data = {
"ticket": 1000007, # this is not a valid ticket number
"payment_amount": 1.00
}
form = PaymentForm(user=user, data=form_data)
self.assertFalse(form.is_valid())
答案 0 :(得分:0)
您需要在代码中添加该要求。好好阅读docs on form and field validation。
有许多地方可以添加验证(例如,在模型上,在表单中的模型字段等)。我建议您按照here所述的形式字段添加验证。
像 -
def clean_ticket(self):
# get your valid ticket queryset
if ticket not in valid_ticket_queryset:
raise forms.ValidationError("You have added an invalid ticket!")
return data