2014-02-13 171 views
1

使用inlineformset_factory我可以添加/刪除與單個客戶相關的電話號碼。唯一的問題是,我想要求每個客戶至少有一個有效的電話號碼。inlineformset_factory最低要求

下面是一些演示代碼:

型號:

class Customer(models.Model): 
    name = models.CharField(max_length=255) 

class PhoneNumber(models.Model): 
    customer = models.ForeignKey(Customer) 
    number = models.CharField(max_length=10) 

形式:

class CustomerForm(ModelForm): 
    class Meta: 
     model = Customer 
     fields = ['name'] 

class PhoneNumberForm(ModelForm): 
    class Meta: 
     model = PhoneNumber 
     fields = ['number'] 

好,所以這是非常直截了當。 然後在我的觀點:

class Create(View): 
    template_name = 'path_to_template' 
    CustomerForm = forms.CustomerForm 
    PhoneNumberFormSet = inlineformset_factory (
     parent_model = Customer, 
     model = PhoneNumber, 
     form = PhoneNumberForm, 
     extra = 1, 
    ) 

    def get(self, request): 
     # Return empty forms 
     context = { 
      'customer_form': self.CustomerForm, 
      'phone_number_formset': self.PhoneNumberFormSet 
     } 
     render(request, self.template_name, context) 

    def post(self, request): 
     this_customer_form = self.CustomerForm(request.POST) 

     if this_customer_form.is_valid(): 
      new_customer.save(commit=False) 
      this_phone_number_formset = self.PhoneNumberFormSet(request.POST, instance=new_customer) 

      if this_phone_number_formset.is_valid(): 
       new_customer.save() 
       this_phone_number_formset.save() 
       return HttpResponseRedirect(reverse_lazy('customer-detail', kwargs={'pk': new_customer.pk})) 

     # Something is not right, show the forms again 
     this_phone_number_formset = self.PhoneNumberFormSet(request.POST) 
     context = { 
      'customer_form': this_customer_form, 
      'phone_number_formset': this_phone_number_formset 
     } 
     render(request, self.template_name, context) 

你得到我認爲這一點。客戶的編輯/更新視圖也是如此。只有這樣,表單纔會被預先填充。

在這一點上,我需要的是一種方法來要求每個客戶至少一個有效的PhoneNumber。 我發現是這樣的:

class RequiredFormSet(BaseFormSet): 
    def __init__(self, *args, **kwargs): 
     super(RequiredFormSet, self).__init__(*args, **kwargs) 
     for form in self.forms: 
      form.empty_permitted = False 

https://stackoverflow.com/questions/2406537/django-formsets-make-first-required 但它似乎沒有工作,當我將此上BaseInlineFormSet類。

Django 1.7似乎回答我的意願,而不是一個InlineModelFormSet至今..

任何想法?

+0

你不能只是使您的PhoneNumber類中的號碼字段是必填字段? – professorDante

+0

@professorDante除非您指定一個空白= True的模型字段,否則默認情況下這將是必需的。 [Django文檔](https://docs.djangoproject.com/en/dev/ref/models/fields/#blank) –

回答

0

謝謝kezabella(django irc)。 我似乎找到了solution通過繼承BaseInlineFormset:

class RequiredFormSet(BaseInlineFormSet): 
    def clean(self): 
     for form in self.initial_forms: 
      if not form.is_valid() or not (self.can_delete and form.cleaned_data.get('DELETE')): 
       return 
     for form in self.extra_forms: 
      if form.has_changed(): 
       return 
     raise ValidationError("No initial or changed extra forms") 

順便說一句,這些驗證錯誤不會在{{formset.error}}出現,但在:

{{ formset.non_form_errors }}