其他分享
首页 > 其他分享> > 第十六课 Django 表单模型(四)

第十六课 Django 表单模型(四)

作者:互联网

第十六课 表单模型(四)

1. 字段输入框的排序

在我们使用 as_p(), as_ul()as_table()快捷方式生成HTML页面的input框时,这些input元素的先后顺序和表单类中字段定义的先后顺序是一致的。

如果想要调整顺序,可以使用Form类的field_order 属性。

默认情况下,Form.field_order=None,表示与字段采用同样顺序。

如果给field_order提供一个列表值,那么首先按列表中列出的项排出,剩下的继续按原顺序排出。如果列表中有无效的字段名,将被忽略。

from django import forms

class MyForm(forms.Form):
    field_order = [...]

2. 判断表单上传类型

Form类有一个is_multipart() 方法,可以用来判断表单是上传文件还是键值对。如下所示:

>>> f = ContactFormWithMugshot()
>>> f.is_multipart()
True

这样,我们就可以在模板中,根据上传方式的不同,生成不同的表头:

{% if form.is_multipart %}
    <form enctype="multipart/form-data" method="post" action="/foo/">
{% else %}
    <form method="post" action="/foo/">
{% endif %}
{{ form }}
</form>

3. 添加前缀

可以为Form类添加prefix属性或参数,来给每个字段名添加一个前缀,比如:

>>> mother = PersonForm(prefix="mother")
>>> father = PersonForm(prefix="father")
>>> print(mother.as_ul())
<li><label for="id_mother-first_name">First name:</label> <input type="text" name="mother-first_name" id="id_mother-first_name" required></li>
<li><label for="id_mother-last_name">Last name:</label> <input type="text" name="mother-last_name" id="id_mother-last_name" required></li>
>>> print(father.as_ul())
<li><label for="id_father-first_name">First name:</label> <input type="text" name="father-first_name" id="id_father-first_name" required></li>
<li><label for="id_father-last_name">Last name:</label> <input type="text" name="father-last_name" id="id_father-last_name" required></li>

或者

>>> class PersonForm(forms.Form):
...     ...
...     prefix = 'person'

4. 创建子类

如果你创建一个Form类的子类,那么子类将自动拥有父类所有的字段。如下所示:

>>> class ContactFormWithPriority(ContactForm):
...     priority = forms.CharField()
>>> f = ContactFormWithPriority(auto_id=False)
>>> print(f.as_ul())
<li>Subject: <input type="text" name="subject" maxlength="100" required></li>
<li>Message: <input type="text" name="message" required></li>
<li>Sender: <input type="email" name="sender" required></li>
<li>Cc myself: <input type="checkbox" name="cc_myself"></li>
<li>Priority: <input type="text" name="priority" required></li>

可以同时继承多个父类:

>>> from django import forms
>>> class PersonForm(forms.Form):
...     first_name = forms.CharField()
...     last_name = forms.CharField()
>>> class InstrumentForm(forms.Form):
...     instrument = forms.CharField()
>>> class BeatleForm(InstrumentForm, PersonForm):
...     haircut_type = forms.CharField()
>>> b = BeatleForm(auto_id=False)
>>> print(b.as_ul())
<li>First name: <input type="text" name="first_name" required></li>
<li>Last name: <input type="text" name="last_name" required></li>
<li>Instrument: <input type="text" name="instrument" required></li>
<li>Haircut type: <input type="text" name="haircut_type" required></li>

在子类中,将某个父类中的字段设置为None,可以声明性地删除这个字段,也就是说子类不要父类的这个字段:

>>> from django import forms

>>> class ParentForm(forms.Form):
...     name = forms.CharField()
...     age = forms.IntegerField()

>>> class ChildForm(ParentForm):
...     name = None

>>> list(ChildForm().fields)
['age']

5. 表单字段

① Field.clean(value)

注意:这里说的是字段Field的clearn方法,不是表单Form的clean方法。

虽然表单字段的Field类主要使用在Form类中,但也可以直接实例化它们来使用,以便更好地了解它们是如何工作的。每个Field的实例都有一个clean()方法,它接受一个参数,然后返回“清洁的”数据或者抛出一个django.forms.ValidationError异常:

>>> from django import forms
>>> f = forms.EmailField()
>>> f.clean('foo@example.com')
'foo@example.com'
>>> f.clean('invalid email address')
Traceback (most recent call last):
...
ValidationError: ['Enter a valid email address.']

这个clean方法经常被我们用来在开发或测试过程中对某个字段的数据进行验证和测试。

② 核心字段参数

1. required

给字段添加必填属性,不能空着。

>>> from django import forms
>>> f = forms.CharField()
>>> f.clean('foo')
'foo'
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: ['This field is required.']
>>> f.clean(None)
Traceback (most recent call last):
...
ValidationError: ['This field is required.']
>>> f.clean(' ')
' '
>>> f.clean(0)
'0'
>>> f.clean(True)
'True'
>>> f.clean(False)
'False'

若要表示一个字段不是必需的,设置required=False:

>>> f = forms.CharField(required=False)
>>> f.clean('foo')
'foo'
>>> f.clean('')
''
>>> f.clean(None)
''
>>> f.clean(0)
'0'
>>> f.clean(True)
'True'
>>> f.clean(False)
'False'

2. label

label参数用来给字段添加“人类友好”的提示信息。如果没有设置这个参数,那么就用字段的首字母大写名字。下面的例子,前两个字段有,最后的comment没有label参数:

>>> from django import forms
>>> class CommentForm(forms.Form):
...     name = forms.CharField(label='Your name')
...     url = forms.URLField(label='Your website', required=False)
...     comment = forms.CharField()
>>> f = CommentForm(auto_id=False)
>>> print(f)
<tr><th>Your name:</th><td><input type="text" name="name" required /></td></tr>
<tr><th>Your website:</th><td><input type="url" name="url" /></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" required /></td></tr>

3. label_suffix

Django默认为上面的label参数后面加个冒号后缀,如果想自定义,可以使用label_suffix参数。比如下面的例子用“?”代替了冒号:

>>> class ContactForm(forms.Form):
...     age = forms.IntegerField()
...     nationality = forms.CharField()
...     captcha_answer = forms.IntegerField(label='2 + 2', label_suffix=' =')
>>> f = ContactForm(label_suffix='?')
>>> print(f.as_p())
<p><label for="id_age">Age?</label> <input id="id_age" name="age" type="number" required /></p>
<p><label for="id_nationality">Nationality?</label> <input id="id_nationality" name="nationality" type="text" required /></p>
<p><label for="id_captcha_answer">2 + 2 =</label> <input id="id_captcha_answer" name="captcha_answer" type="number" required /></p>

4. initial

为HTML页面中表单元素定义初始值。也就是input元素的value参数的值,如下所示:

>>> from django import forms
>>> class CommentForm(forms.Form):
...     name = forms.CharField(initial='Your name')
...     url = forms.URLField(initial='http://')
...     comment = forms.CharField()
>>> f = CommentForm(auto_id=False)
>>> print(f)
<tr><th>Name:</th><td><input type="text" name="name" value="Your name" required /></td></tr>
<tr><th>Url:</th><td><input type="url" name="url" value="http://" required /></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" required /></td></tr>

你可能会问为什么不在渲染表单的时候传递一个包含初始化值的字典给它,不是更方便?因为如果这么做,你将触发表单的验证过程,此时输出的HTML页面将包含验证中产生的错误,如下所示:

>>> class CommentForm(forms.Form):
...     name = forms.CharField()
...     url = forms.URLField()
...     comment = forms.CharField()
>>> default_data = {'name': 'Your name', 'url': 'http://'}
>>> f = CommentForm(default_data, auto_id=False)
>>> print(f)
<tr><th>Name:</th><td><input type="text" name="name" value="Your name" required /></td></tr>
<tr><th>Url:</th><td><ul class="errorlist"><li>Enter a valid URL.</li></ul><input type="url" name="url" value="http://" required /></td></tr>
<tr><th>Comment:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="comment" required /></td></tr>

这就是为什么initial参数只用在未绑定的表单上。

还要注意,如果提交表单时某个字段的值没有填写,initial的值不会作为“默认”的数据。initial值只用于原始表单的显示:

>>> class CommentForm(forms.Form):
...     name = forms.CharField(initial='Your name')
...     url = forms.URLField(initial='http://')
...     comment = forms.CharField()
>>> data = {'name': '', 'url': '', 'comment': 'Foo'}
>>> f = CommentForm(data)
>>> f.is_valid()
False
# The form does *not* fall back to using the initial values.
>>> f.errors
{'url': ['This field is required.'], 'name': ['This field is required.']}

除了常量之外,你还可以传递一个可调用的对象:

>>> import datetime
>>> class DateForm(forms.Form):
...     day = forms.DateField(initial=datetime.date.today)
>>> print(DateForm())
<tr><th>Day:</th><td><input type="text" name="day" value="12/23/2008" required /><td></tr>

5. widget

最重要的参数之一,指定渲染Widget时使用的widget类,也就是这个form字段在HTML页面中是显示为文本输入框?密码输入框?单选按钮?多选框?还是别的…

6. help_text

该参数用于设置字段的辅助描述文本

>>> from django import forms
>>> class HelpTextContactForm(forms.Form):
...     subject = forms.CharField(max_length=100, help_text='100 characters max.')
...     message = forms.CharField()
...     sender = forms.EmailField(help_text='A valid email address, please.')
...     cc_myself = forms.BooleanField(required=False)
>>> f = HelpTextContactForm(auto_id=False)
>>> print(f.as_table())
<tr><th>Subject:</th><td><input type="text" name="subject" maxlength="100" required /><br /><span class="helptext">100 characters max.</span></td></tr>
<tr><th>Message:</th><td><input type="text" name="message" required /></td></tr>
<tr><th>Sender:</th><td><input type="email" name="sender" required /><br />A valid email address, please.</td></tr>
<tr><th>Cc myself:</th><td><input type="checkbox" name="cc_myself" /></td></tr>
>>> print(f.as_ul()))
<li>Subject: <input type="text" name="subject" maxlength="100" required /> <span class="helptext">100 characters max.</span></li>
<li>Message: <input type="text" name="message" required /></li>
<li>Sender: <input type="email" name="sender" required /> A valid email address, please.</li>
<li>Cc myself: <input type="checkbox" name="cc_myself" /></li>
>>> print(f.as_p())
<p>Subject: <input type="text" name="subject" maxlength="100" required /> <span class="helptext">100 characters max.</span></p>
<p>Message: <input type="text" name="message" required /></p>
<p>Sender: <input type="email" name="sender" required /> A valid email address, please.</p>
<p>Cc myself: <input type="checkbox" name="cc_myself" /></p>

7. error_messages

该参数允许你覆盖字段引发异常时的默认信息。 传递的是一个字典,其键为你想覆盖的错误信息。 例如,下面是默认的错误信息:

>>> from django import forms
>>> generic = forms.CharField()
>>> generic.clean('')
Traceback (most recent call last):
  ...
ValidationError: ['This field is required.']

而下面是自定义的错误信息:

>>> name = forms.CharField(error_messages={'required': 'Please enter your name'})
>>> name.clean('')
Traceback (most recent call last):
  ...
ValidationError: ['Please enter your name']

8. validators

指定一个列表,其中包含了为字段进行验证的函数。也就是说,如果你自定义了验证方法,不用Django内置的验证功能,那么要通过这个参数,将字段和自定义的验证方法链接起来

9. localize

localize参数帮助实现表单数据输入的本地化

10. disabled

设置有该属性的字段在前端页面中将显示为不可编辑状态。

该参数接收布尔值,当设置为True时,使用HTML的disabled属性禁用表单域,以使用户无法编辑该字段。即使非法篡改了前端页面的属性,向服务器提交了该字段的值,也将依然被忽略

11.has_changed()方法

和Form类似,每个Field也有一个has_changed()方法,用于判断字段的值是否发生了改变

③ 表单内置的Field

1. BooleanField

2. CharField

有四个可选参数:

3. ChoiceField

参数choices:用来作为该字段选项的一个二元组组成的可迭代对象(例如,列表或元组)或者一个可调用对象。格式与用于和ORM模型字段的choices参数相同。

4. TypedChoiceField

像ChoiceField一样,只是还有两个额外的参数:coerce和empty_value。

5. DateField

接收一个可选的参数:input_formats。一个格式的列表,用于转换字符串为datetime.date对象。

如果没有提供input_formats,默认的输入格式为:

['%Y-%m-%d',      # '2006-10-25'
 '%m/%d/%Y',      # '10/25/2006'
 '%m/%d/%y']      # '10/25/06'

另外,如果你在设置中指定USE_L10N=False,以下的格式也将包含在默认的输入格式中:

['%b %d %Y',      # 'Oct 25 2006'
 '%b %d, %Y',     # 'Oct 25, 2006'
 '%d %b %Y',      # '25 Oct 2006'
 '%d %b, %Y',     # '25 Oct, 2006'
 '%B %d %Y',      # 'October 25 2006'
 '%B %d, %Y',     # 'October 25, 2006'
 '%d %B %Y',      # '25 October 2006'
 '%d %B, %Y']     # '25 October, 2006'

6. DateTimeField

接收一个可选的参数:input_formats

如果没有提供input_formats,默认的输入格式为:

['%Y-%m-%d %H:%M:%S',    # '2006-10-25 14:30:59'
 '%Y-%m-%d %H:%M',       # '2006-10-25 14:30'
 '%Y-%m-%d',             # '2006-10-25'
 '%m/%d/%Y %H:%M:%S',    # '10/25/2006 14:30:59'
 '%m/%d/%Y %H:%M',       # '10/25/2006 14:30'
 '%m/%d/%Y',             # '10/25/2006'
 '%m/%d/%y %H:%M:%S',    # '10/25/06 14:30:59'
 '%m/%d/%y %H:%M',       # '10/25/06 14:30'
 '%m/%d/%y']             # '10/25/06'

7. DecimalField

接收四个可选的参数:

8. DurationField

9. EmailField

两个可选的参数用于验证,max_length和min_length

10. FileField

具有两个可选的参数用于验证:max_length 和 allow_empty_file

11. FilePathField

这个字段允许从一个特定的目录选择文件。

参数:

12. FloatField

接收两个可选的参数用于验证,max_value和min_value,控制允许的值的范围

13. ImageField

使用ImageField需要安装Pillow库

>>> from PIL import Image
>>> from django import forms
>>> from django.core.files.uploadedfile import SimpleUploadedFile
>>> class ImageForm(forms.Form):
...     img = forms.ImageField()
>>> file_data = {'img': SimpleUploadedFile('test.png', <file data>)}
>>> form = ImageForm({}, file_data)
# Pillow closes the underlying file descriptor.
>>> form.is_valid()
True
>>> image_field = form.cleaned_data['img']
>>> image_field.image
<PIL.PngImagePlugin.PngImageFile image mode=RGBA size=191x287 at 0x7F5985045C18>
>>> image_field.image.width
191
>>> image_field.image.height
287
>>> image_field.image.format
'PNG'
>>> image_field.image.getdata()
# Raises AttributeError: 'NoneType' object has no attribute 'seek'.
>>> image = Image.open(image_field)
>>> image.getdata()
<ImagingCore object at 0x7f5984f874b0>

14. IntegerField
**

两个可选参数:max_value和min_value,控制允许的值的范围

15.JSONField

Django3.1新增,接收JSON编码的字段

16. GenericIPAddressField

包含IPv4或IPv6地址的字段

有两个可选参数:protocol和unpack_ipv4

17. MultipleChoiceField

18. TypedMultipleChoiceField

类似MultipleChoiceField,除了需要两个额外的参数,coerce和empty_value

19. NullBooleanField

20.RegexField

参数:

21. SlugField

此字段用于在表单中表示模型的SlugField

22. TimeField

接收一个可选的参数:input_formats,用于尝试将字符串转换为有效的datetime.time对象的格式列表

如果没有提供input_formats,默认的输入格式为:

'%H:%M:%S',     # '14:30:59'
'%H:%M',        # '14:30'

23. URLField

可选参数:max_length和min_length

24. UUIDField

25. ComboField

接收一个额外的必选参数:fields,用于验证字段值的字段列表(按提供它们的顺序)

>>> from django.forms import ComboField
>>> f = ComboField(fields=[CharField(max_length=20), EmailField()])
>>> f.clean('test@example.com')
'test@example.com'
>>> f.clean('longemailaddress@example.com')
Traceback (most recent call last):
...
ValidationError: ['Ensure this value has at most 20 characters (it has 28).']

26. MultiValueField

27. SplitDateTimeField

④ 创建自定义字段

如果内置的Field真的不能满足你的需求,还可以自定义Field

只需要创建一个django.forms.Field的子类,并实现clean()和__init__()构造方,__init__()构造方法需要接收前面提过的那些核心参数,比如widget、required,、label、help_text、initial,还可以通过覆盖get_bound_field()方法来自定义访问字段的方式

标签:第十六,Widget,...,required,默认,表单,forms,invalid,Django
来源: https://blog.csdn.net/zly717216/article/details/111242863