django表单验证基于字段是否有价值

时间:2011-01-18 11:04:40

标签: django django-forms django-validation

  1. 当我提交一个选中了phone_type的空表单(对于formHomePhone)时,表单会返回自己,而不会在phone_type中选择This field is required UKPhoneNumberField < / p>

  2. 从视图中可以看出表格中的第一个电话号码是必需的,但其他电话号码不是。如果存在值,我只想处理它们。虽然当我在空表单上点击提交时,其他电话号码字段会从Phone number must include an area code.&gt;中引发错误。 def new_client_view(request): if request.method == 'POST': formDetails = ClientDetailsForm(request.POST) formAddress = ClientAddressForm(request.POST) formHomePhone = ClientPhoneForm(request.POST) formWorkPhone = ClientOtherPhoneForm(request.POST) formMobilePhone = ClientOtherPhoneForm(request.POST) if formDetails.is_valid() and formAddress.is_valid() and formHomePhone.is_valid(): c = Client() c.save() fd = formDetails.save(commit=False) fd.client = c fd.created_by = request.user fd.save() fa = formAddress.save(commit=False) fa.client = c fa.created_by = request.user fa.save() fph = formHomePhone.save(commit=False) fph.client = c fph.created_by = request.user fph.save() if 'p2-number' in request.POST and request.POST['p2-number']: fpw = formWorkPhone.save(commit=False) fpw.client = c.id fpw.created_by = request.user if fpw.is_valid(): fpw.save() if 'p3-number' in request.POST and request.POST['p3-number']: fpm = formMobilePhone.save(commit=False) fpm.client = c fpm.created_by = request.user if fpm.is_valid(): fpm.save() return render_to_response('client/client.html', context_instance=RequestContext(request)) else: return render_to_response('client/new_client.html', {'formDetails': formDetails, 'formAddress': formAddress, 'formHomePhone': formHomePhone, 'formWorkPhone': formWorkPhone, 'formMobilePhone': formMobilePhone}, context_instance=RequestContext(request)) else: formAddress = ClientAddressForm() formDetails = ClientDetailsForm() formHomePhone = ClientPhoneForm(initial={'phone_type':'home'}, prefix="p1") formWorkPhone = ClientPhoneForm(initial={'phone_type':'work'}, prefix="p2") formMobilePhone = ClientPhoneForm(initial={'phone_type':'mobi'}, prefix="p3") return render_to_response('client/new_client.html', {'formDetails': formDetails, 'formAddress': formAddress, 'formHomePhone': formHomePhone, 'formWorkPhone': formWorkPhone, 'formMobilePhone': formMobilePhone}, context_instance=RequestContext(request)) 如何才能在尊重字段中存在数字时进行验证?

  3. 我有一个像这样的view.py文件

    class ClientDetailsForm(ModelForm):
        class Meta:
            model = ClientDetails
            exclude = ('client', 'created', 'created_by')
    
    class ClientAddressForm(ModelForm):
        class Meta:
            model = ClientAddress
            exclude = ('client', 'created', 'created_by')
    
    class ClientPhoneForm(ModelForm):
        number = UKPhoneNumberField()
    
        class Meta:
            model = ClientPhone
            exclude = ('client', 'created', 'created_by')
    
    class ClientOtherPhoneForm(ModelForm):
        number = UKPhoneNumberField(required=False)
    
        class Meta:
            model = ClientPhone
            exclude = ('client', 'created', 'created_by')
    

    像这样的forms.py:

    MARITAL_STATUS_CHOICES = (
        ...
    )
    
    NAME_TITLE_CHOICES = (
        ...
    )
    
    PHONE_CHOICES = (
        ('home', 'Home'),
        ('home2', 'Home 2'),
        ('mobi', 'Mobile'),
        ('mobi2', 'Mobile 2'),
        ('work', 'Work'),
        ('work2', 'Work 2'),
    )
    
    class Client(models.Model):
        closed = models.DateTimeField(blank=True, null=True)
        closed_by = models.ForeignKey(User, blank=True, null=True)
        comment = models.TextField(blank=True, null=True)
    
        def __unicode__(self):
            return u'%s' % (self.id)
    
    class ClientDetails(models.Model):
        ...
    
    class ClientAddress(models.Model):
        ...
    
    class ClientPhone(models.Model):
        client = models.ForeignKey(Client, null=True)
        created = models.DateTimeField(default=datetime.now)
        created_by = models.ForeignKey(User, blank=True, null=True)
        phone_type = models.CharField(max_length=5, choices=PHONE_CHOICES)
        number = models.CharField(max_length=24)
    

    和models.py这样:

    new_client_view

    BTW(我的{{1}}功能不是很干我知道。会很感激地收到任何建议。

2 个答案:

答案 0 :(得分:8)

如果要在ModelForm字段为空时停止验证,请在模型定义中设置blank = True,null = True。

如果您不想更改模型,可以覆盖ModelForm中的required attr(参见下文),但请记住,form.save()方法可能会尝试保留null DB期望非空值的值。

class FooForm(forms.ModelForm):

    class Meta:
         #exclude etc as you wish

    def __init__(self, *args, **kwargs):

         #init the form as usual
         super(FooForm, self).__init__(*args, **kwargs)

         #then change the required status on the fields:
         self.fields['baz'].required = False

<强>更新 这是一个完全不同的方法,因为OP的评论似乎意味着形式之间的验证可能是他所追求的:

如果您希望当前某个表单基于另一种形式的某种方式表现出来,那么您就是在谈论跨表单验证,这是不可能的,因为表单的清理方法不容易识别任何其他表单表格由该视图处理。

相反,我建议创建一个新的forms.Form类,它包含您要处理的模型的所有字段,但不是ModelForm。然后,您可以向该表单添加save()(或process()或其他)方法,这些方法将执行您在视图中当前拥有的fandango。这可能会使你的代码稍微整洁。

您需要将request.user作为参数传递给表单(kwarg更容易正确),以便您可以在要保存的模型上设置适当的用户。

但是,当然,我们不要忘记验证,我建议您在该表单的主要clean()方法中进行验证,该方法可以访问您需要处理的所有字段。

所以,作为一些快速未经测试的代码:

from django import forms
from django.forms.util import ErrorList

class ClientForm(forms.Form):

    ## define your fields here ##
    home_phone = forms.CharField(required=False) 
    # etc etc

    def __init__(self, *args, **kwargs):
        """
        NB: in the view you'll need to call the form's constructor with 
        keyword arguments for client (the client whose details are being 
        edited) and user (ie: request.user)
        """

        #before the form is initialised, grab the two extra objects we'll 
        #need in save()

        self.client = kwargs.pop('client') 
        #NB:this will explode if there is no client kwarg present

        self.user = kwargs.pop('user') #ditto, for a 'user' argument

        #now carry on with the standard form initialisation
        super(ClientForm, self).__init__(*args, **kwargs)


    def clean(self):

        #probe your cleaned data here and enforce any cross-field dependencies you wish

        if self.cleaned_data.get('foo') and not self.cleaned_data.get('bar'):
            self._errors['foo'] = ErrorList(["A Foo should only be present if there\'s not a Bar"])
            # NB: only override a value in an _errors dict if you're sure there is 
            # nothing in there already (ie: the foo field has been cleaned and is 
            # present in cleaned_data)
            # Otherwise, you should append() a string to the ErrorList in question

        return self.cleaned_data

    def save(self):

        #what you have in the view is doing a lot of the legwork, so extend that
        #code here to get or create the relevant ClientHomePhone etc models
        #based on lookups related to self.client, which we set in __init__() above

        #also, remember you'll have access to self.user which is the user who is 
        #creating/editing so you can set this for created_by

        return self.client # or some other relevant entity, if you wish

答案 1 :(得分:0)

我找到了类似这样的答案(是的,我知道这很愚蠢!)

def new_client_view(request):
    if request.method == 'POST':
        formDetails = ClientDetailsForm(request.POST)
        formAddress = ClientAddressForm(request.POST)
        formHomePhone = ClientPhoneForm(request.POST)
        if formDetails.is_valid() and formAddress.is_valid() and formHomePhone.is_valid():
            c = Client()
            c.save()
            fd = formDetails.save(commit=False)
            fd.client = c
            fd.created_by = request.user
            fd.save()
            fa = formAddress.save(commit=False)
            fa.client = c
            fa.created_by = request.user
            fa.save()
            fph = formHomePhone.save(commit=False)
            fph.client = c
            fph.created_by = request.user
            fph.save()
            if 'p2-number' in request.POST and request.POST['p2-number']:
                formWorkPhone = ClientOtherPhoneForm(request.POST)
                fpw = formWorkPhone.save(commit=False)
                fpw.client = c.id
                fpw.created_by = request.user
                # if the work number is valid
                if fpw.is_valid():
                    # check the mobile number before you save the work number
                    if 'p3-number' in request.POST and request.POST['p3-number']:
                        formMobilePhone = ClientOtherPhoneForm(request.POST)
                        fpm = formMobilePhone.save(commit=False)
                        fpm.client = c
                        fpm.created_by = request.user
                        # if the mobile number is good then there is no more checking to do
                        if fpm.is_valid():
                            fpm.save()
                        # else load up the form again with the error for the mobile phone and the original
                        # data for the mobile phone and the work phone
                        else:
                            formWorkPhone = ClientOtherPhoneForm(request.POST)
                            return render_to_response('client/new_client.html', {'formDetails': formDetails, 'formAddress': formAddress, 'formHomePhone': formHomePhone, 'formWorkPhone': formWorkPhone, 'formMobilePhone': formMobilePhone}, context_instance=RequestContext(request))
                    # if the work number is valid and the mobile field wasn't used then just save the work number
                    fpw.save()
                # if the work number is not valid then find out if a mobile number
                # was entered and feed it back to the form
                else:
                    if 'p3-number' in request.POST and request.POST['p3-number']:
                        formMobilePhone = ClientOtherPhoneForm(request.POST)
                    else:
                        formMobilePhone = ClientPhoneForm(initial={'phone_type':'mobi'}, prefix="p3")
                    return render_to_response('client/new_client.html', {'formDetails': formDetails, 'formAddress': formAddress, 'formHomePhone': formHomePhone, 'formWorkPhone': formWorkPhone, 'formMobilePhone': formMobilePhone}, context_instance=RequestContext(request))

            return render_to_response('client/client.html', context_instance=RequestContext(request))
        # if the form doesn't validate then you need to find out if the optional fields contain data,
        # and if so load that data back into the form
        else:
            if 'p2-number' in request.POST and request.POST['p2-number']:
                formWorkPhone = ClientOtherPhoneForm(request.POST, prefix="p2")
            else:
                formWorkPhone = ClientPhoneForm(initial={'phone_type':'work'}, prefix="p2")
            if 'p3-number' in request.POST and request.POST['p3-number']:
                formMobilePhone = ClientOtherPhoneForm(request.POST, prefix="p3")
            else:
                formMobilePhone = ClientPhoneForm(initial={'phone_type':'mobi'}, prefix="p3")

            return render_to_response('client/new_client.html', {'formDetails': formDetails, 'formAddress': formAddress, 'formHomePhone': formHomePhone, 'formWorkPhone': formWorkPhone, 'formMobilePhone': formMobilePhone}, context_instance=RequestContext(request))


    else:
        formAddress = ClientAddressForm()
        formDetails = ClientDetailsForm()
        formHomePhone = ClientPhoneForm(initial={'phone_type':'home'}, prefix="p1")
        formWorkPhone = ClientPhoneForm(initial={'phone_type':'work'}, prefix="p2")
        formMobilePhone = ClientPhoneForm(initial={'phone_type':'mobi'}, prefix="p3")
        return render_to_response('client/new_client.html', {'formDetails': formDetails, 'formAddress': formAddress, 'formHomePhone': formHomePhone, 'formWorkPhone': formWorkPhone, 'formMobilePhone': formMobilePhone}, context_instance=RequestContext(request))

我认为我需要覆盖表单上的is_valid函数,以确保在执行类似super.is_valid()之前在其中一个字段中有数据(否则返回true,所以我不会提高表单上的pre-save函数,表单上有一个user函数,它将clientis_valid()个对象放入字段,并在保存前检查是否有电话号码。< / p>

  1. 覆盖pre-save()以确保空白值可以通过
  2. 创建User以将Clientnumber加载到模型中,如果phone_type
  3. 没有值,则可以中止

    这太疯狂了!!!

    我唯一能想到的是在number模型ClientPhone中设置blank=True, null=Trueclass ClientDetailsForm(ModelForm): class Meta: model = ClientDetails exclude = ('client', 'created', 'created_by') def CustomSave(self,c,u): t = self.save(commit=False) t.client = c t.created_by = u t.first_name = self.cleaned_data['first_name'].capitalize() t.middle_name = self.cleaned_data['first_name'].capitalize() t.last_name = self.cleaned_data['first_name'].capitalize() t.save() class ClientAddressForm(ModelForm): class Meta: model = ClientAddress exclude = ('client', 'created', 'created_by') def CustomSave(self,c,u): t = self.save(commit=False) t.client = c t.created_by = u t.address_1 = self.cleaned_data['address_1'].capitalize() t.address_2 = self.cleaned_data['address_2'].capitalize() t.address_3 = self.cleaned_data['address_3'].capitalize() t.address_4 = self.cleaned_data['address_4'].capitalize() t.post_code = self.cleaned_data['post_code'].upper() t.save() class ClientPhoneForm(ModelForm): number = UKPhoneNumberField() class Meta: model = ClientPhone exclude = ('client', 'created', 'created_by') def CustomSave(self,c,u): t = self.save(commit=False) t.client = c t.created_by = u t.save() class ClientOtherPhoneForm(ModelForm): number = UKPhoneNumberField(required=False) class Meta: model = ClientPhone exclude = ('client', 'created', 'created_by') def CustomSave(self,c,u): t = self.save(commit=False) t.client = c t.created_by = u t.save() ,以便我可以选择手机字段

    那太疯狂了!!!

    为什么我必须打破模型的完整性只是为了在我的一个表单中有一个选项字段???

    编辑:

    当我对forms.py文件执行以下操作时,

    view.py变得更干净了:

    {{1}}