_姜3

2018-06-19  本文已影响15人  dittoyy3991

@form表单
form使用HTML5语法,顶部需添加<!DOCTYPE html>说明

from .forms import NameForm
from django.core.mail import send_mail
if request.method == 'POST':
        # 接受request.POST参数构造form类的实例
        form = NameForm(request.POST)
        # 验证数据是否合法
        if form.is_valid():
            #form.cleaned_data字典中读取所有的表单数据
            subject = form.cleaned_data['subject']
            message = form.cleaned_data['message']
            sender = form.cleaned_data['sender']
            cc_myself = form.cleaned_data['cc_myself']

            recipients = ['info@example.com']
            if cc_myself:
                    recipients.append(sender)

            send_mail(subject, message, sender, recipients)
            return HttpResponseRedirect('/thanks/')

from django import forms
class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    message = forms.CharField(widget=forms.Textarea)
    sender = forms.EmailField()
    cc_myself = forms.BooleanField(required=False)

= = =

#template表单渲染格式
Django自动为每个input元素设置了一个id名称,对应label的for参数。
{{ form.as_p }}
{{ form.as_ul }}
{{ form.as_table }}

#手动渲染表单字段
{{ form.non_field_errors }}
<div class="fieldWrapper">
    {{ form.subject.errors }}
    <label for="{{ form.subject.id_for_label }}">Email subject:</label>#{{ form.subject.label_tag }}
    {{ form.subject }}
</div>

#渲染表单错误信息errorlist
{% if form.subject.errors %}
    <ol>
    {% for error in form.subject.errors %}
        <li><strong>{{ error|escape }}</strong></li>
    {% endfor %}
    </ol>
{% endif %}

#循环表单的字段
{% for field in form %}
    <div class="fieldWrapper">
        {{ field.errors }}
        {{ field.label_tag }} {{ field }}
        {% if field.help_text %}
        <p class="help">{{ field.help_text|safe }}</p>
        {% endif %}
    </div>
{% endfor %}

#不可见字段特殊处理hidden_fields()和visible_fields()
{# 循环那些不可见的字段 #}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{# 循环可见的字段 #}
{% for field in form.visible_fields %}
    <div class="fieldWrapper">
        {{ field.errors }}
        {{ field.label_tag }} {{ field }}
    </div>
{% endfor %}

#重用表单模板  include+with参数,给每个表单模板取个别名
{% include "form_snippet.html" with form=comment_form %}
使用{% for field in comment_form %}
# 单独的表单模板文件form_snippet.html:
{% for field in form %}
    <div class="fieldWrapper">
        {{ field.errors }}
        {{ field.label_tag }} {{ field }}
    </div>
{% endfor %}

= = =

1 表单的绑定属性
Form.is_bound True/False
f= ContactForm()#新建一个未绑定的表单
data={'name':anna,'age':12,'marriage':True}
f= ContactForm(date)#绑定了
即使data={}也算绑定

2 使用表单验证数据
Form.clean()
Form.is_valid()#验证数据是否合适的布尔值

3 Form.errors属性保存了错误信息字典
- f.errors
{'sender': ['Enter a valid email address.'], 'subject': ['This field is required.']}
- Form.errors.as_data()返回一个字典,将字段映射到原始的ValidationError实例
{'sender': [ValidationError(['Enter a valid email address.'])],
'subject': [ValidationError(['This field is required.'])]}
- Form.errors.as_json(escape_html=False)返回序列化后的错误字典
{"sender": [{"message": "Enter a valid email address.", "code": "invalid"}],
"subject": [{"message": "This field is required.", "code": "required"}]}

4 Form.add_error(field, error)向特定字段添加错误信息

5 Form.has_error(field, code=None)判断某个字段是否有指定code错误,当code为None任何错误均返回True

6 Form.non_field_errors()返回Form.errors中不是与特定字段相关联的错误

7 Form.has_changed()表单是否发生了变化
f = ContactForm(data, initial=data)
f.has_changed()#表单是否发生了变化True、False

8 Form.changed_data返回有变化的字段的列表
f = ContactForm(request.POST, initial=data)#
if f.has_changed():
    print("The following fields changed: %s" % ", ".join(f.changed_data))

9 通过fileds属性访问表单的字段
for row in f.fields.values(): print(row)
f.fields['name']
f.as_table().split('\n')[0]#显示tr里的第一个
f.fields['name'].label = "Username"#修改name字段为Username

10 f.cleaned_data不仅负责验证数据还会将其转为正确的格式
cleaneddata只包含合法的字段,只包含Form定义的字段,data里没赋值的值是空
f.cleaned_data
{'nick_name': '', 'first_name': 'John', 'last_name': 'Lennon'}

11 如果表单是绑定的输出的html将包含数据data


###渲染
f = ContactForm()
f.as_table()
Form.as_p()
Form.as_url()
Form.as_table()

= = =

将上传的文件绑定到表单*处理带有FileField和ImageField字段
为了上传文件,你需要确保你的<form>元素定义enctype为"multipart/form-data":
<form enctype="multipart/form-data" method="post" action="/foo/">
# 为表单绑定image字段
文件数据的处理与普通的表单数据是分开的,所以如果表单包含FileField和ImageField,绑定表单时你需要指定第二个参数
>>> from django.core.files.uploadedfile import SimpleUploadedFile
>>> data = {'subject': 'hello',
...         'message': 'Hi there',
...         'sender': 'foo@example.com',
...         'cc_myself': True}
>>> file_data = {'mugshot': SimpleUploadedFile('face.jpg', <file data>)}
>>> f = ContactFormWithMugshot(data, file_data)

一般使用request.FILES作为文件数据的源:
# Bound form with an image field, data from the request
>>> f = ContactFormWithMugshot(request.POST, request.FILES)

核心字段
>>> from django import forms
>>> f = forms.CharField(required=False)
>>> f.clean('foo')
'foo'
>>> f.clean(' ')
' '
>>> f.clean(0)
'0'

label()添加人类友好提示,若无,则为该字段首字母大写
>>> 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>
>>> print tf['name'].label_tag()#输出label
Your name:

label_suffixDjango默认为上面的label参数后面加个冒号后缀
>>> 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>

initial()给表单元素定义初始值*input元素的value参数的值
如data没有填值的话,initial的值不会作为“默认”的数据。initial值只用于原始表单的显示
>>> class CommentForm(forms.Form):
...     name = forms.CharField(initial='Your name')
...     url = forms.URLField(initial='http://')
...     comment = forms.CharField()
...     day = forms.DateField(initial=datetime.date.today)#传入一个可调用的对象
>>> 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>

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

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

help_text该参数用于设置字段的辅助描述文本
subject = forms.CharField(max_length=100, help_text='100 characters max.')
f = HelpTextContactForm(auto_id=False)
print f.as_table()


error_messages该参数允许你覆盖字段引发异常时的默认信息。 传递的是一个字典,其键为你想覆盖的错误信息
name = forms.CharField(error_messages={'required': 'Please enter your name'})#如果error是因为required导致的

validators指定一个列表,其中包含了为字段进行验证的函数

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

disabled设置有该属性的字段在前端页面中将显示为不可编辑状态
即使非法篡改了前端页面的属性,向服务器提交了该字段的值,也将依然被忽略




***内置Field类型

|field|css|data|
|:--|:-|:-|
|BooleanField | CheckboxInput | required|
|CharField max_length | TextInput | min_length strip empty_value required|
|ChoiceField | Select | required invalid_choice|
|TypedChoiceField | Select | required invalid_choice coerce empty_value|
|DateField | DateInput | input_formats required invalid %Y-%m-%d|
|DateTimeField | DateTimeInput |  input_formats required invalid'%Y-%m-%d %H:%M:%S'|
|DurationField | TextInput | min_length invalid required|
|EmailField | EmailInput | min_length required invalid|
|FileField | ClearableFileInput | missing, invalid, required, empty, max_length max_length allow_empty_file|
|FilePathField | Select | required invalid_choice  path recursive match allow_files allow_folders|
|FloatField | NumberInput TextInput | max_value, invalid, required, min_value|
|ImageField | ClearableFileInput | missing, invalid, required, empty, invalid_image pillow|
|IntegerField | NumberInput TextInput | max_value, invalid, required, min_value|
|GenericIPAddressField | TextInput | protocol unpack_ipv4|
|MultipleChoiceField | SelectMultiple | invalid_list, invalid_choice, required|
|TypedMultipleChoiceField | SelectMultiple | invalid_list, invalid_choice, required coerce empty_value|
|NullBooleanField|
|RegexField | TextInput | max_length,min_length和strip参数,类似CharField|
|SlugField | TextInput | 
|TimeField | TextInput | '%H:%M:%S'|
|URLField | UrlInput | 
|UUIDField | TextInput | 
|ComboField |
|MultiValueField |
|MultiValueField |
|SplitDateTimeField |


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

= = =

###widget
@指定使用的widget
每个字段都有一个默认的widget类型。如果你想要使用一个不同的Widget,可以在定义字段时使用widget参数。 像这样:
from django import forms
class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField(widget=forms.Textarea)#覆盖原来的TextInput Widget

@widget添加css特殊属性
可以在创建Widget时使用Widget.attrs参数来实现这一目的:
class CommentForm(forms.Form):
    name = forms.CharField(widget=forms.TextInput(attrs={'class': 'special'}))
    url = forms.URLField()
    comment = forms.CharField(widget=forms.TextInput(attrs={'size': '40'}))

@许多widget具有可选的额外参数,下面的示例中,设置了SelectDateWidget的years 属性,注意参数的传递方法:
from django import forms
BIRTH_YEAR_CHOICES = ('1980', '1981', '1982')
FAVORITE_COLORS_CHOICES = (
    ('blue', 'Blue'),
    ('green', 'Green'),
    ('black', 'Black'),
)

class SimpleForm(forms.Form):
    birth_year = forms.DateField(widget=forms.SelectDateWidget(years=BIRTH_YEAR_CHOICES))
    favorite_colors = forms.MultipleChoiceField(
        required=False,
        widget=forms.CheckboxSelectMultiple,
        choices=FAVORITE_COLORS_CHOICES,
    )

@Meta类内部的widgets属性
from django.forms import ModelForm, Textarea
from myapp.models import Author
class AuthorForm(ModelForm):
    class Meta:
        model = Author
        fields = ('name', 'title', 'birth_date')
        widgets = {
            'name': Textarea(attrs={'cols': 80, 'rows': 20}), # 改写name属性
        }

将fields属性的值设为__all__,表示将映射的模型中的全部字段都添加到表单类中来。
from django.forms import ModelForm
class AuthorForm(ModelForm):
    class Meta:
        model = Author
        fields = '__all__'
exclude属性:
表示将model中,除了exclude属性中列出的字段之外的所有字段,添加到表单类中作为表单字段。
class PartialAuthorForm(ModelForm):
    class Meta:
        model = Author
        exclude = ['title']



上一篇下一篇

猜你喜欢

热点阅读