Django表单验证基于字段是否有值
当我提交一个选择了
phone_type
的空表单(对于formHomePhone
)时,表单返回其自身,而没有在phone_type
中选择的值规定此字段是必需的
正如您从视图中看到的那样,表单中的第一个电话号码是必需的,但其他电话号码不是。我只想在存在价值的情况下处理它们。尽管当我在空表单上单击“提交”时,附加电话号码字段会从
UKPhoneNumberField
> 中抛出错误。电话号码必须包含区号。
如何仅在相关字段中有号码时进行验证?
我有一个像这样的 view.py 文件
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))
,一个像这样的 forms.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')
和一个像这样的 models.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)
顺便说一句(我知道我的 new_client_view
函数不是很干。任何建议都是非常感谢)
When I submit an empty form with a
phone_type
selected (forformHomePhone
) the form returns its self without a value selected inphone_type
stipulatingThis field is required
As you can see from the view The first phone number in the form is required but the other phone numbers are not. I only want to process them if there is a value present. Though when I click submit on an empty form the additional phone number fields throw up an error from the
UKPhoneNumberField
>Phone number must include an area code.
How can I only validate when there is a number in the respected field?
I have a view.py file like this
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))
a forms.py like this:
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')
and a models.py like this:
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)
BTW(my new_client_view
function is not very DRY I know. Any recommendations would be gratefully received)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果要在 ModelForm 字段为空时停止对其进行验证,请在模型定义中设置 Blank=True、null=True。
如果您不想更改模型,可以覆盖 ModelForm 中的
required
attr(见下文),但请记住,您的 form.save() 方法可能会尝试保留 null数据库期望非空值的值。更新
这是一种完全不同的方法,考虑到OP的评论似乎暗示表单之间的验证可能就是他所追求的:
如果您希望当前的表单基于另一种表单中的内容以某种方式运行,那么您正在谈论交叉 -表单验证,这是不可能的,因为表单的清理方法不容易意识到该视图正在处理的任何其他表单。
相反,我建议创建一个新的 forms.Form 类,其中包含您想要处理的模型的所有字段,但它不是 ModelForm。然后,您可以向该表单添加一个
save()
(或process()
或其他)方法,该方法将执行您当前视图中的 fandango。这也可能使您的代码稍微整洁一些。您需要将 request.user 作为参数传递到表单中(kwarg 更容易正确),以便您可以在要保存的模型上设置适当的用户。
但是,当然,我们不要忘记验证,我建议您在该表单的主要 clean() 方法中进行验证,该方法将可以访问您需要处理的所有字段。
因此,作为一些快速未经测试的代码:
If you want to stop ModelForm fields being validated when they're empty, set blank=True, null=True in the model definition.
If you don't want to change the model, you can override the
required
attr in the ModelForm (see below), but bear in mind then that your form.save() method may try to leave null values where the DB expects non-nulls.UPDATE
Here's a totally different approach, given that the OP's comments seem to imply that validation between forms may be what he's after:
If you want one of your current forms to behave a certain way based on what's in another form, you're talking cross-form validation, which isn't possible as the cleaning methods of forms are not easily aware of any other forms being handled by that view.
Instead, I'd recommend making a new forms.Form class that has all the fields of the models you want to deal with, but which is not a ModelForm. You can then add a
save()
(orprocess()
or whatever) method to that Form that will do the fandango you currently have in your view. That may make your code slightly neater, too.You'll need to pass in the request.user into the form as an argument (a kwarg is easier to get right) so that you can set the appropriate user on the models you're saving.
But of course, let's not forget about the validation, which I recommend you do in the main clean() method of that form, which will have access to all the fields you need to juggle.
So, as some quick untested code:
我找到了一个类似这样的答案(是的,我知道这很愚蠢!)
我想我需要覆盖表单上的
is_valid
函数,以确保在执行某项操作之前其中一个字段中有数据像super.is_valid()
(否则返回 true,这样我就不会为空表单引发错误)以及表单上的presave
函数,该函数采用user
和client
对象,并将它们放入字段中,并在保存之前检查是否有电话号码。is_valid()
以确保空白值可以通过pre-save()
加载到User
和Client 进入模型,如果可以的话,如果
number 没有值
就中止这太疯狂了!!!
我唯一能想到的就是制作
和ClientPhone
模型中的phone_typenumber
blank=True, null=True
以便我可以拥有可选的电话字段这也太疯狂了!!!
为什么我必须破坏模型的完整性才能在我的表单之一中拥有一个选项字段???
编辑:
当我对 forms.py 文件执行以下操作时,view.py 变得更干净:
I found an answer that goes something like this (yes I know it's stupid!)
I think I need to overwrite the
is_valid
function on the form to make sure there is data in one of the fields before doing something likesuper.is_valid()
(else returning true so I don't raise an error for an empty form) and also apre-save
function on the form that takes theuser
andclient
objects and puts them into the fields and checks there is a phone number before saving.is_valid()
to make sure blank values can get throughpre-save()
to load inUser
andClient
into the model and abort if you can if there is no value fornumber
THIS IS CRAZY!!!
The only other thing I can think of is making
phone_type
andnumber
in theClientPhone
modelblank=True, null=True
so that I can have optional phone fieldsTHATS CRAZY AS WELL!!!
Why should I have to break the integrity of my model just to have an option field in one of my forms???
EDIT:
view.py turned out cleaner when I did the following to the forms.py file: