2009-12-31 24 views
0

我创建的视图,其返回包括接触形式和两个PHONE_NUMBER形式形式,以下这个例子中直列形式,才需要:django的内联编辑如果至少一个字段被填充了

multiple forms

的只有当用户在电话号码表格中插入至少一个字段的值时,才能验证电话号码表单。例如:电话号码有一个类型和一个号码。如果用户选择类型,则该号码是必需的。

现在我想知道如何在视图中检查用户是否插入了值/选定的类型或插入了一个数字。它应该像管理员一样工作,用于内联编辑模型。

我的看法是这样的:首先如下响应之后

def contact_add(request): 
    user = request.user 
    if request.method == 'POST': 
     cform = ContactForm(request.POST) 
     pforms = [PhoneNumberForm(request.POST, prefix=str(x)) for x in range(0,3)] 
     if cform.is_valid() and all([pf.is_valid() for pf in pforms]): 
      new_contact = cform.save(commit=False) 
      new_contact.created_by = user 
      new_contact.save() 
      for pf in pforms: 
       new_phone_number = pf.save(commit=False) 
       new_phone_number.contact = new_contact 
       new_phone_number.save() 
      request.user.message_set.create(message='Contact %s has been added.' % new_contact.__str__()) 
      return HttpResponseRedirect("/crm/contacts/?oby=1") 

    else: 
     cform = ContactForm() 
     pforms = [PhoneNumberForm(prefix=str(x)) for x in range(0,3)] 

    return render_to_response(
     'crm/contact_add.html', 
     {'cform': cform, 'pforms': pforms,}, 
     context_instance = RequestContext(request), 
    ) 

编辑:

我试图实现与自定义验证这个任务,但没来一个令人满意的结束。为了缓解我的任务,我改变了一些用例。我创建了一个包含一个联系表和一个地址表的表单。只有填写了地址表单中的至少一个字段时,才能验证地址表单,因为应该可以在不创建相应地址的情况下创建联系人。

首先,我试图用custome验证,这是这样的:

class AddressForm(forms.ModelForm): 
    class Meta: 
     model = Address 
     exclude = ('contact',) 

    def clean(self): 
     cleaned_data = self.cleaned_data 
     street = cleaned_data.get("street") 
     postal_code = cleaned_data.get("postal_code") 
     city = cleaned_data.get("city") 
     country = cleaned_data.get("country") 

     if not street and not postal_code and not city and not country: 
      #searching a better idea here 
      return 0 
     else: 
      return cleaned_data 

但是,这并不能真正帮助,因为这样一来我不摆脱验证错误。

这使我想到,干净的方法是做错误的地方做这个验证,我想我必须检查POST.request中是否所有地址表单的值都丢失。如果他们错过了,我不会为地址表单调用is_valid(),而忽略它。如果至少有一个值可用,我只需执行地址表单的常规验证,而不必重写clean()方法。

好的或坏的主意? 如果这是一个好主意,我怎样才能轻松地检查POST请求的地址表单的值。

也许我真的思维方式复杂:-)

编辑:该解决方案使用表单集:

@login_required 
def contact_add(request): 
    user = request.user 
    if request.method == 'POST': 
     cform = ContactForm(request.POST) 
     phonenumberformset = PhoneNumberFormSet(request.POST) 

     if cform.is_valid() and classificationformset.is_valid() and addressformset.is_valid() and phonenumberformset.is_valid(): 
      new_contact = cform.save(commit=False) 
      new_contact.created_by = user 
      new_contact.save() 

      new_phonenumber_instances = phonenumberformset.save(commit=False) 
      for new_phonenumber in new_phonenumber_instances: 
       new_phonenumber.contact = new_contact 
       new_phonenumber.save() 

      request.user.message_set.create(message='Contact %s has been added.' % new_contact.__str__()) 
      return HttpResponseRedirect("/crm/contacts/?oby=1") 
    else: 
     cform = ContactForm() 
     #By default, when you create a formset from a model, the formset will use 
     #a queryset that includes all objects in the model (e.g., Author.objects.all()). 
     #Here we want to present an empty formset in order to add a new object 

     phonenumberformset = PhoneNumberFormSet(queryset=PhoneNumber.objects.none()) 
    return render_to_response(
     'crm/contact_add.html', 
     {'cform': cform, 'phonenumberformset': phonenumberformset,}, 
     context_instance = RequestContext(request), 
    ) 

请注意,这也可以实现使用inlineformset_factory,看到我的其他职位更多详细信息:link

请注意,如果您使用FormSets,则必须在模板中为每个form_set包含一个management_form。 docs

否则,你得到这个错误:

[u'ManagementForm data is missing or has been tampered with'] 

Using a formset inside a view is as easy as using a regular Form class. The only thing you will want to be aware of is making sure to use the management form inside the template.

{{ context.phonenumberformset.management_form }} 

回答

2

您应该使用formsets,而不是与你的******中国窗体动态前缀乱搞 - 它将使一切变得更加容易,而这确实是管理员管理内联表单的方式(另请参阅model formsets documentation)。

Formset足够智能,如果没有信息输入到formset的一种形式中,它不强制执行所需的元素 - 但是如果填充了一个元素,它将强制执行所有验证要求。这听起来像它应该解决你的问题。

+0

Formsets?从来没有听说过。将尝试它。听起来不错:-) – 2010-01-01 13:20:18

+0

但是对于我上面的用例,如果我为一个地址表单创建一个Formset。 formset会检查用户是否填充了数据并且不会验证它? – 2010-01-01 13:26:48

+0

好吧,它的工作。将尝试其他内联,并在我的问题中发布结果! – 2010-01-01 14:17:45

2

你想要做什么形式的定义custom validation

class PhoneNumberForm(forms.Form): 
    # Everything as before. 
    ... 

    def clean(self): 
     cleaned_data = self.cleaned_data 
     phone1 = cleaned_data.get("phone1") 

     if phone1: 
      # validate manually, and if it doesn't pass: 
      self._errors["phone1"] = ErrorList(["Hey, this field is wrong."]) 
      del cleaned_data["phone1"]    

     # Always return the full collection of cleaned data. 
     return cleaned_data 

然后在视图中,要依靠Django的内置错误表单验证错误处理:

{{ pforms.phone1 }} 
{{ pforms.phone1.errors }} 
相关问题