2013-02-18 3 views
1

ModelForm에 대한 단위 테스트를 개발 중입니다. 정의 된 쿼리 세트 내에서 선택할 수없는 값을 전달할 때 폼의 ModelChoiceField가 invalid_choice ValidationError를 발생시키지 않고 있음을 발견했습니다. 필드.Django ModelChoiceField가 유효하지 않은 선택을 위해 ValidationError를 발생시키지 않습니다.

나는 그 이유는 do_python()은 https://docs.djangoproject.com/en/1.4/ref/forms/validation/#form-and-field-validation에서 말하는 것처럼 ModelChoiceField에 대한 to_python()이 먼저 호출되지 않았거나 to_python()이 양식의 모델과 모델의 깨끗한 메소드를 호출하기 전에 DoesNotExist 예외를 포착하지 않았기 때문이라고 생각한다. 어떤 원인이 처리되지 않은 예외가 아래에 포함 :

예상하고 invalid_choice 오류가 발생으로
# 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 메소드가 to_python 메소드보다 먼저 호출되고 있음을 알려줍니다.

여기에 무슨 일이 일어나는지 이해하게 도와주세요. 이 테스트를 어떻게 할 수 있습니까? 나는 장고 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

코드에 해당 요구 사항을 추가해야합니다. 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 
+0

그래서 난 그냥이 시도하고 그것은 여전히 ​​위와 같은 오류를했다. 그러나 문서를 다시 읽은 후에 필드 및 필드 유효성 검사에서 유효성 검사 오류가 발생하더라도 양식 및 모델 정리 메서드가 항상 실행된다는 문제가 있다고 생각합니다. 그래서 제가 한 것은 모델 레벨의 예외를 잡아서 유효성 검사 오류를 발생시키는 것입니다. 이제는 게시하기 전에 클라이언트 측에서 양식을 수정하는 경우 사용자가 스팸 메일을받지 못하도록 방지하는 데에만 유용합니다. – Anand

관련 문제