2014-02-13 5 views
1

Использование inlineformset_factory Я могу добавлять/удалять номера телефонов, относящиеся к одному клиенту. Проблема только в том, что я хочу потребовать по крайней мере 1 действительный номер телефона для каждого клиента.inlineformset_factory required required

Вот некоторые демо-код:

Модели:

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'] 

Ok, так что это довольно прямо вперед. Тогда на мой взгляд:

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) 

Вы получите точку, я думаю. То же самое для представления Edit/Update клиента. Только тогда формы препопыляются.

На данный момент все, что мне нужно, это способ потребовать хотя бы 1 действительного номера телефона на одного клиента. я нашел что-то вроде:

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 Docs] (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") 

Btw, эти ошибки проверки не отображаются в {{}} formset.error но:

{{ formset.non_form_errors }}