一 创建一个form组件

 导入forms模块组件:from django import forms

 创建组件:创建一个类继承者forms.Form这个类

 类型:

  CharField:字符串类型,min_length:字符长度不能小于多少;max_length:字符的长度不能大于多少,error_messages:可以根据保存信息显示对应的中文报错,required:该字段不能够为空,widget:对input标签操作。

  IntegerField:整数类型,invalid:格式错误

  MultiplechioceField:设置字段为多选框(单选框)。initial=[数字,]:初始个数。choices=((value,数据),(value,数据)):为多选框(单选框赋值)。widgets.CheckboxSelectMultiple:设置为复选框

 其他类型:

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类型
    ...
View Code

 根据不同要求为表单加上不同的属性值:导入from django.forms impost widgets

  widgets.PasswoedInput:加上密文的属性值,addrs:为指定的标签加上属性。

  widgets.TextInput:文本信息

  widgets.Select:下拉菜单,choices:为option出入值和value属性值

 钩子clean:首先导入异常:from django.core.exceptions import ValidationError。

  局部钩子:clean_字段名,就是使用clean_加上一个字段名。用于字段校验

    raise calidationsError:抛出错误信息

    cleaned_data:如果符合条件,数据就会存放在这里面,可以使用get获取是一个有序的字典格式,从上往下依次判断添加。

 for name, field in self.fields.items():
              try:

                    value = field.clean(value)
                    self.cleaned_data[name] = value
                    if hasattr(self, 'clean_%s' % name):
                        value = getattr(self, 'clean_%s' % name)()
                        self.cleaned_data[name] = value
              except ValidationError as e:
                    self.add_error(name, e)

  全局钩子:clean,直接在这个函数里面定义功能,可以用于多个字段的操作和比较,直接可以获取cleaned_data里面的数据。

    __all__:全局抛出来的错误存放在这个里面的。

        self.clean()     # def self.clean():return self.cleaned_data
        return  not self.errors    # True或者False    
from django import forms
from django.forms import widgets
from django.core.exceptions import ValidationError


class LoginForm(forms.Form):

    user=forms.CharField(min_length=5,max_length=12,
                         error_messages={
                              "required":"该字段不能为空",
                              "min_length":"该字段的长度不能小于5",
                              "max_length":"该字段的长度不能大于12"},
                         widget=widgets.TextInput(attrs={"class":"form-control"})
                         )


    pwd=forms.CharField(
        error_messages={
            "invalid": "必须是数字"
        },
        widget=widgets.PasswordInput(attrs={"class":"form-control",})
    )

    gender=forms.CharField(
        widget=widgets.Select(choices=((1,''),(0,''),))
    )

    usersss = forms.MultipleChoiceField(
        initial=[2, ],
        choices=((1, '上海'), (2, '北京'),),
        widget=widgets.CheckboxSelectMultiple
    )


    def clean_user(self):
       print("============",self.cleaned_data.get("pwd"))  # ============ None
       if  not self.cleaned_data.get("user").isdigit():

           return self.cleaned_data.get("user")
       else:
           raise ValidationError("该字段不能是纯数字")



    def clean_pwd(self):
        print("-----------------",self.cleaned_data.get("user"))
        import re
        val=self.cleaned_data.get("pwd")
        ret=re.findall("^\d{6}yuan$",val)
        if ret:
            return val
        else:
            raise ValidationError("密码不符合设定要求")

    def clean(self):


        if self.cleaned_data.get("user") and self.cleaned_data.get("pwd"):
            if self.cleaned_data.get("user") != self.cleaned_data.get("pwd"):
                return self.cleaned_data

            else:
                raise ValidationError("用户名与密码不能一致!")

        return self.cleaned_data
View Code

 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
View Code

 常用选择插件:

# 单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
# )
View Code

二 实例form对象

实例化时:
        self.fields={
            "username":"字段规则对象",
            "password":"字段规则对象",

        }

 LoginForm:form自建实例的对象存放的地点,request.POST:将数据传递给对应的字段,绑定数据的表单实例

 is_valid:校验,将检验是否符合要求,返回的是一个布尔值

  cleaned_data:检验正确数据就存放在这里面,是以字典的格式存放的,出数据。

  errors:检验没有通过或错误的信息存放在这个里面,是以字典的格式存放的。errors.get获取里面的某些数据。

from django.shortcuts import render,HttpResponse

# Create your views here.

from django import forms
from .models import *

from django.forms import widgets

from .forms import *



def login(request):
    if request.method=="POST":
        #print(request.POST) #<QueryDict: {'csrfmiddlewaretoken': ['0xrifjX7jplIZwngbrRjpHPXw6kyDVa2Erca0sGYfjH9UuDfHzNUdMzlh7EH2v44'], 'user': ['asdas'], 'pwd': ['12321321']}>
        login_form=LoginForm(request.POST) # 将数据传给对应字段  绑定数据的表单实例

        '''
            #   self.cleaned_data={"pwd":"12312412"}      
            #   self.errors={"user":"yuan",}
        '''
        if login_form.is_valid():
            print("通过验证")
            print(login_form.cleaned_data)
            print("use:",login_form.cleaned_data.get("user"))
            print(login_form.errors)
            ###############
            # user=login_form.cleaned_data.get("user")
            # pwd=login_form.cleaned_data.get("pwd")
            # UserInfo.objects.filter(username=user,password=pwd)
            # UserInfo.objects.filter(**login_form.cleaned_data)

            return HttpResponse("OK")
        else:
            # print("验证失败")
            # print(login_form.cleaned_data) # {'pwd': 77777}
            # print(login_form.errors)
            # ################## login_form.errors是什么类型
            # print(type(login_form.errors))# <class 'django.forms.utils.ErrorDict'>
            # ###################获取login_form.errors的某个键的值
            # print(login_form.errors.get("user"))
            # print(type(login_form.errors.get("pwd")))# <class 'django.forms.utils.ErrorList'>
            #
            # #login_form.errors={"user":["小于5位","不是数字"],"pwd":["",""]}
            errors=login_form.errors# {"user":["该字段不能是纯数字",],"pwd":["",""]}
            print("errors-->",errors)

            error_all=errors.get("__all__")
            return render(request, "login.html", {"login_form": login_form,"errors":errors,"error_all":error_all})

    #### get请求

    login_form=LoginForm()   # form组件的实例对象   未绑定表单实例
    return render(request,"login.html",{"login_form":login_form})
View Code

三 html文件渲染

 模板导入input标签:直接用对象.字段取出内容  {{ 对象.字段}}

 模板导入错误信息:直接使用srrors.字段名.0取出数据{{ srrors.字段名.0 }}

 form组件只能够直接渲染input标签,form标签还是需要自己写的。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!-- 新 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
    <style>
        .container{
            margin-top: 100px;

        }
    </style>
</head>
<body>


<div class="container">
    <div class="row">
        <div class="col-md-6">

            <form action="/login/" method="post">
                 {% csrf_token %}
                  <div class="form-group">
                    <label for="user">user</label>
                    {{ login_form.user }} <span>{{ errors.user.0 }}</span>
                  </div>
                  <div class="form-group">
                    <label for="pwd">pwd</label>
                    {{ login_form.pwd }} <span>{{ errors.pwd.0 }}</span>
                  </div>
                   <div class="form-group">
                    <label for="gender">gender</label>
                    {{ login_form.gender }}<span>{{ error_all.0 }}</span>
                  </div>

                 <p>{{ login_form.usersss }}</p>

                  <button type="submit" class="btn btn-default">Submit</button>
                </form>
            <hr>
{#            <form action="">#}
{#                {{ login_form.as_p }}#}
{#            </form>#}

        </div>
    </div>
</div>

</body>
</html>
View Code

四 其他渲染对象

对于<label>/<input> 对,还有几个输出选项:

  • {{ form.as_table }} 以表格的形式将它们渲染在<tr> 标签中
  • {{ form.as_p }} 将它们渲染在<p> 标签中
  • {{ form.as_ul }} 将它们渲染在<li> 标签中

注意,你必须自己提供<table> 或<ul> 元素。

{{ form.as_p }}结果如下:

<form action="">
    <p>
        <label for="id_username">Username:</label>
        <input id="id_username" maxlength="100" name="username" type="text" required="">
    </p>
 
 
    <p>
        <label for="id_password">Password:</label>
        <input id="id_password" maxlength="100" name="password" placeholder="password" type="password" required="">
    </p>
 
 
    <p>
        <label for="id_telephone">Telephone:</label> <input id="id_telephone" name="telephone" type="number" required="">
    </p>
 
 
    <p>
        <label for="id_email">Email:</label> <input id="id_email" name="email" type="email" required="">
    </p>
 
 
    <p>
        <label for="id_is_married">Is married:</label> <input id="id_is_married" name="is_married" type="checkbox">
    </p>
 
 
    <input type="submit" value="注册">
</form>
View Code

 这种渲染有了限制,不能个自定义的渲染,而是将所有的字段全部渲染过去。

手动渲染:我们没有必要非要让Django 来分拆表单的字段;如果我们喜欢,我们可以手工来做每个字段都是表单的一个属性,可以使用{{ form.name_of_field }} 访问,并将在Django 模板中正确地渲染

<div class="fieldWrapper">
    {{ form.Username.errors }}
    {{ form.Username.label_tag }}
    {{ form.Username }}
</div>

 五 表单渲染的错误信息

registerForm=RegisterForm(request.POST)
print(type(registerForm.errors))                      #<class 'django.forms.utils.ErrorDict'>
print(type(registerForm.errors["username"]))          #<class 'django.forms.utils.ErrorList'> 
使用{{ form.name_of_field.errors }} 显示表单错误的一个清单,并渲染成一个ul。看上去可能像:
<ul class="errorlist">
    <li>Sender is required.</li>
</ul>

 

 

补充练习:

from django.shortcuts import render

# Create your views here.
from .models import UserInfor

from django.forms import ModelForm
from django import forms

from .models import *

print(City.objects.all().values_list("id","name"))

# class RegForm(forms.Form):
#     user = forms.CharField(max_length=32)
#     #gender_tuple=(0,'上海'),(1,'北京'),(2,'保定')
#     gender = forms.ChoiceField(choices =City.objects.all().values_list("id","name"))
#
#     def __init__(self,*args,**kwargs):
#         super(RegForm,self).__init__(*args,**kwargs)
#         #print("Ok")
#         print(self.fields["gender"].choices)
#         self.fields["gender"].choices=City.objects.all().values_list("id","name")


'''
class UserInfor(models.Model):
    user=models.CharField(max_length=32)
    gender=models.IntegerField(choices=((1,"男"),(2,"女")))
    city=models.ForeignKey("City",default=1)
    roles=models.ManyToManyField("Roles",default=1)
|||||

class UserInfor(forms.Form):
    user=forms.CharField()
    gender=forms.TypedChoiceField(choices=((1,"男"),(2,"女")))
    city=forms.ModelChoiceField(choices=City.objects.all())
    roles=forms.ModelMultipleChoiceField(choices=Roles.objects.all())
'''

class RegForm(ModelForm):
    class Meta:
        model=UserInfor
        fields="__all__"

def reg(reqeust):
    form=RegForm()
    print(form.fields)

    return render(reqeust,"reg.html",{"form":form})
View Code

 

 

posted on 2017-12-14 16:55  方少0410  阅读(201)  评论(0编辑  收藏  举报