Django之Form组件

Form表单介绍

Django的Form主要具有一下几大功能:

  • 生成HTML标签
  • 验证用户数据(显示错误信息)
  • HTML Form提交保留上次提交数据
  • 初始化页面显示内容

简单使用form组件

创建Form类

from django.shortcuts import render,HttpResponse,redirect
from app01 import models
from django import forms
from django.forms import fields,widgets
import json
from django.core.validators import RegexValidator  #扩展正则表达式
from django.core.exceptions import ValidationError
# Create your views here.
class TestForm(forms.Form):
    user=fields.CharField(
        label="用户名",
        max_length=32,
        min_length=4,
        required=True, # 是否必填
        error_messages={
            'min_length':'最少4个字节',
            'max_length':'最多32个字节',
            'required':'不能为空',
            'invalid':'格式错误'},  # 错误提示信息
        initial="dada",  # 默认值
        widget=widgets.TextInput(attrs={'class':"c2"}),  # 自定制html插件
        # disabled=True,   # 不可填
        show_hidden_initial=True,   # 在后面加多一个input框,验证数据是否发生变化"
    )

    age=fields.IntegerField(
        label='年龄',
        max_value=150,
        min_value=0,
    )

    # img=fields.FileField()  #上传文件

    email=fields.EmailField(
        label='邮箱'
    )

    gender=fields.ChoiceField(
        label='性别',
        choices=[(1,""),(2,'')],
        initial=1,
        widget=widgets.RadioSelect()
    )

    hobby=fields.MultipleChoiceField(
        label='爱好',
        choices=[(1,"篮球"),(2,"足球"),(3,"排球")],
        initial=[1,2],
        widget=widgets.SelectMultiple(attrs={"class":'c1'}),
    )

View函数处理

def test(request):
    if request.method=="GET":
        obj=TestForm()
        return render(request,'test.html',{"obj":obj})

    if request.method=='POST':
        obj=TestForm(request.POST) #将数据交给form类进行验证

        if obj.is_valid():
            print(obj.cleaned_data) #验证成功后,所有的数据都会在cleaned_data中
            #可以直接插入数据库中
            return HttpResponse("OK")
        else:
            # 若有错误,打印错误信息
            return render(request,'test.html',{"obj":obj})

生成HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="/test/" method="post" enctype="multipart/form-data">
    {% csrf_token %}
    <p>{{ obj.user.label }}:{{ obj.user }} {{ obj.user.errors.0 }}</p>
    <p>{{ obj.age.label }}:{{ obj.age }} {{ obj.age.errors.0 }}</p>
    <p>{{ obj.gender.label }}:{{ obj.gender }} {{ obj.gender.errors.0 }}</p>
    <p>{{ obj.email.label }}:{{ obj.email }} {{ obj.email.errors.0 }}</p>
    <p>{{ obj.hobby.label }}:{{ obj.hobby }} {{ obj.hobby.errors.0 }}</p>
    <p><input type="submit"></p>
    
    {# 可以用for循环来生成标签 #}
{#    {% for item in obj %}#}
{#        <p>{{ item.label }}:{{ item }}{{ item.errors.0 }}</p>#}
{#    {% endfor %}#}
{#    <p><input type="submit"></p>#}

</form>

</body>
</html>

Form类

常用字段与插件

initial

初始值,input框里面的初始值。

class LoginForm(forms.Form):
    username = forms.CharField(
        min_length=8,
        label="用户名",
        initial="张三"  # 设置默认值
    )
    pwd = forms.CharField(min_length=6, label="密码")

error_messages

重写错误信息。

class LoginForm(forms.Form):
    username = forms.CharField(
        min_length=8,
        label="用户名",
        initial="张三",
        error_messages={
            "required": "不能为空",
            "invalid": "格式错误",
            "min_length": "用户名最短8位"
        }
    )
    pwd = forms.CharField(min_length=6, label="密码")

password

class LoginForm(forms.Form):
    ...
    pwd = forms.CharField(
        min_length=6,
        label="密码",
        widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True)
    )

radioSelect

单radio值为字符串

class LoginForm(forms.Form):
    username = forms.CharField(
        min_length=8,
        label="用户名",
        initial="张三",
        error_messages={
            "required": "不能为空",
            "invalid": "格式错误",
            "min_length": "用户名最短8位"
        }
    )
    pwd = forms.CharField(min_length=6, label="密码")
    gender = forms.fields.ChoiceField(
        choices=((1, ""), (2, ""), (3, "保密")),
        label="性别",
        initial=3,
        widget=forms.widgets.RadioSelect()
    )

单选Select

class LoginForm(forms.Form):
    ...
    hobby = forms.fields.ChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
        label="爱好",
        initial=3,
        widget=forms.widgets.Select()
    )

多选Select

class LoginForm(forms.Form):
    ...
    hobby = forms.fields.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.SelectMultiple()
    )

单选checkbox

class LoginForm(forms.Form):
    ...
    keep = forms.fields.ChoiceField(
        label="是否记住密码",
        initial="checked",
        widget=forms.widgets.CheckboxInput()
    )

多选checkbox

class LoginForm(forms.Form):
    ...
    hobby = forms.fields.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.CheckboxSelectMultiple()
    )

创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML;

Django内置字段如下

Field
    required=True,               是否允许为空
    widget=None,                 HTML插件
    label=None,                  用于生成Label标签或显示内容
    initial=None,                初始值
    help_text='',                帮助信息(在标签旁边显示)
    error_messages=None,         错误信息 {'required': '不能为空', 'invalid': '格式错误'}
    show_hidden_initial=False,   是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
    validators=[],               自定义验证规则
    localize=False,              是否支持本地化
    disabled=False,              是否可以编辑
    label_suffix=None            Label内容后缀
 
 
CharField(Field)
    max_length=None,             最大长度
    min_length=None,             最小长度
    strip=True                   是否移除用户输入空白
 
IntegerField(Field)
    max_value=None,              最大值
    min_value=None,              最小值
 
FloatField(IntegerField)
    ...
 
DecimalField(IntegerField)
    max_value=None,              最大值
    min_value=None,              最小值
    max_digits=None,             总长度
    decimal_places=None,         小数位长度
 
BaseTemporalField(Field)
    input_formats=None          时间格式化   
 
DateField(BaseTemporalField)    格式:2015-09-01
TimeField(BaseTemporalField)    格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
 
DurationField(Field)            时间间隔:%d %H:%M:%S.%f
    ...
 
RegexField(CharField)
    regex,                      自定制正则表达式
    max_length=None,            最大长度
    min_length=None,            最小长度
    error_message=None,         忽略,错误信息使用 error_messages={'invalid': '...'}
 
EmailField(CharField)      
    ...
 
FileField(Field)
    allow_empty_file=False     是否允许空文件
 
ImageField(FileField)      
    ...
    注:需要PIL模块,pip3 install Pillow
    以上两个字典使用时,需要注意两点:
        - form表单中 enctype="multipart/form-data"
        - view函数中 obj = MyForm(request.POST, request.FILES)
 
URLField(Field)
    ...
 
 
BooleanField(Field)  
    ...
 
NullBooleanField(BooleanField)
    ...
 
ChoiceField(Field)
    ...
    choices=(),                选项,如:choices = ((0,'上海'),(1,'北京'),)
    required=True,             是否必填
    widget=None,               插件,默认select插件
    label=None,                Label内容
    initial=None,              初始值
    help_text='',              帮助提示
 
 
ModelChoiceField(ChoiceField)
    ...                        django.forms.models.ModelChoiceField
    queryset,                  # 查询数据库中的数据
    empty_label="---------",   # 默认空显示内容
    to_field_name=None,        # HTML中value的值对应的字段
    limit_choices_to=None      # ModelForm中对queryset二次筛选
     
ModelMultipleChoiceField(ModelChoiceField)
    ...                        django.forms.models.ModelMultipleChoiceField
 
 
     
TypedChoiceField(ChoiceField)
    coerce = lambda val: val   对选中的值进行一次转换
    empty_value= ''            空值的默认值
 
MultipleChoiceField(ChoiceField)
    ...
 
TypedMultipleChoiceField(MultipleChoiceField)
    coerce = lambda val: val   对选中的每一个值进行一次转换
    empty_value= ''            空值的默认值
 
ComboField(Field)
    fields=()                  使用多个验证,如下:即验证最大长度20,又验证邮箱格式
                               fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
 
MultiValueField(Field)
    PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
 
SplitDateTimeField(MultiValueField)
    input_date_formats=None,   格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
    input_time_formats=None    格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
 
FilePathField(ChoiceField)     文件选项,目录下文件显示在页面中
    path,                      文件夹路径
    match=None,                正则匹配
    recursive=False,           递归下面的文件夹
    allow_files=True,          允许文件
    allow_folders=False,       允许文件夹
    required=True,
    widget=None,
    label=None,
    initial=None,
    help_text=''
 
GenericIPAddressField
    protocol='both',           both,ipv4,ipv6支持的IP格式
    unpack_ipv4=False          解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
 
SlugField(CharField)           数字,字母,下划线,减号(连字符)
    ...
 
UUIDField(CharField)           uuid类型
    ...

Django内置插件

TextInput(Input)
NumberInput(TextInput)
EmailInput(TextInput)
URLInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
CheckboxInput
Select
NullBooleanSelect
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
ClearableFileInput
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget

常用选择插件

# 单radio,值为字符串
# user = fields.CharField(
#     initial=2,
#     widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
# )
 
# 单radio,值为字符串
# user = fields.ChoiceField(
#     choices=((1, '上海'), (2, '北京'),),
#     initial=2,
#     widget=widgets.RadioSelect
# )
 
# 单select,值为字符串
# user = fields.CharField(
#     initial=2,
#     widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
# )
 
# 单select,值为字符串
# user = fields.ChoiceField(
#     choices=((1, '上海'), (2, '北京'),),
#     initial=2,
#     widget=widgets.Select
# )
 
# 多选select,值为列表
# user = fields.MultipleChoiceField(
#     choices=((1,'上海'),(2,'北京'),),
#     initial=[1,],
#     widget=widgets.SelectMultiple
# )
 
 
# 单checkbox
# user = fields.CharField(
#     widget=widgets.CheckboxInput()
# )
 
 
# 多选checkbox,值为列表
# user = fields.MultipleChoiceField(
#     initial=[2, ],
#     choices=((1, '上海'), (2, '北京'),),
#     widget=widgets.CheckboxSelectMultiple
# )

实时更新数据

方式一

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
 
class MyForm(Form):
 
    user = fields.ChoiceField(
        # choices=((1, '上海'), (2, '北京'),),
        initial=2,
        widget=widgets.Select
    )
 
    def __init__(self, *args, **kwargs):
        super(MyForm,self).__init__(*args, **kwargs)
        # self.fields['user'].widget.choices = ((1, '上海'), (2, '北京'),)
        #
        self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id','caption')

方式二

使用django提供的ModelChoiceField和ModelMultipleChoiceField字段来实现

from django import forms
from django.forms import fields
from django.forms import widgets
from django.forms import models as form_model
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
 
class FInfo(forms.Form):
    authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())
    # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())

自定义验证规则

方式一

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
 
class MyForm(Form):
    user = fields.CharField(
        validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
    )

方式二

import re
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.exceptions import ValidationError
 
 
# 自定义验证规则
def mobile_validate(value):
    mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
    if not mobile_re.match(value):
        raise ValidationError('手机号码格式错误')
 
 
class PublishForm(Form):
 
 
    title = fields.CharField(max_length=20,
                            min_length=5,
                            error_messages={'required': '标题不能为空',
                                            'min_length': '标题最少为5个字符',
                                            'max_length': '标题最多为20个字符'},
                            widget=widgets.TextInput(attrs={'class': "form-control",
                                                          'placeholder': '标题5-20个字符'}))
 
 
    # 使用自定义验证规则
    phone = fields.CharField(validators=[mobile_validate, ],
                            error_messages={'required': '手机不能为空'},
                            widget=widgets.TextInput(attrs={'class': "form-control",
                                                          'placeholder': u'手机号码'}))
 
    email = fields.EmailField(required=False,
                            error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
                            widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))

钩子函数

每个字段都可以进行再进行验证,比如查看数据库是否有这个人..等等

def clean_+files字段

from django import forms
    from django.forms import fields
    from django.forms import widgets
    from django.core.exceptions import ValidationError
    from django.core.validators import RegexValidator
 
    class FInfo(forms.Form):
        username = fields.CharField(max_length=5,
                                    validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.', 'invalid')], )
        email = fields.EmailField()
 
        def clean_username(self):
            """
            Form中字段中定义的格式匹配完之后,执行此方法进行验证
            :return:
            """
            value = self.cleaned_data['username']
            if "666" in value:
                raise ValidationError('666已经被玩烂了...', 'invalid')
            return value

 

def clean 再执行完clean_+字段

    def clean(self):
        # 整体联合判断错误验证
        value_dict=self.cleaned_data
        data1=value_dict.get('username')
        data2=value_dict.get('user_id')
        if data1=="chen" and  data2==1:
            raise ValidationError("整体出错放在__all__里面")
        return self.cleaned_data

初始化数据

在Web应用程序中开发编写功能时,时常用到获取数据库中的数据并将值初始化在HTML中的标签上。

Form

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
 
 
class MyForm(Form):
    user = fields.CharField()
 
    city = fields.ChoiceField(
        choices=((1, '上海'), (2, '北京'),),
        widget=widgets.Select
    )

Views

from django.shortcuts import render, redirect
from .forms import MyForm
 
 
def index(request):
    if request.method == "GET":
        values = {'user': 'root', 'city': 2}
        obj = MyForm(values)
 
        return render(request, 'index.html', {'form': obj})
    elif request.method == "POST":
        return redirect('http://www.google.com')
    else:
        return redirect('http://www.google.com')

HTML

<form method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    <p>{{ form.user }} {{ form.user.errors }}</p>
    <p>{{ form.city }} {{ form.city.errors }}</p>
 
    <input type="submit"/>
</form>

 

posted @ 2018-08-23 21:21  R00M  阅读(248)  评论(0编辑  收藏  举报