首页 > 代码库 > haha

haha

HTML表单

在HTML中,表单是<form>...</form> 之间元素的集合,它们允许访问者输入文本、选择选项、操作对象和控制等等,然后将信息发送回服务器。

某些表单的元素 —— 文本输入和复选框 —— 非常简单而且内建于HTML 本身。其它的表单会复杂些;例如弹出一个日期选择对话框的界面、允许你移动滚动条的界面、使用JavaScript 和CSS 以及HTML 表单<input> 元素来实现操作控制的界面。与<input> 元素一样,一个表单必须指定两样东西:

  1. 目的地:响应用户输入数据的URL
  2. 方式:发送数据所使用的HTTP 方法

例如,Django Admin 站点的登录表单包含几个<input> 元素:type="text" 用于用户名,type="password" 用于密码,type="submit" 用于“Log in" 按钮。它还包含一些用户看不到的隐藏的文本字段,Django 使用它们来决定下一步的行为。

它还告诉浏览器表单数据应该发往<form> 的action 属性指定的URL —— /admin/,而且应该使用method 属性指定的HTTP 方法 —— post。

当触发<input type="submit" value="http://www.mamicode.com/Log in"> 元素时,数据将发送给/admin/。

Django 中的表单

Django 的Form 类

表单系统的核心部分是Django 的Form 类。Django 的模型描述一个对象的逻辑结构、行为以及展现给我们的方式,与此类似,Form 类描述一个表单并决定它如何工作和展现。

就像模型类的属性映射到数据库的字段一样,表单类的字段会映射到HTML 的<input>表单的元素。

表单字段在浏览器中呈现给用户的是一个HTML 的“widget” —— 用户界面的一个片段。每个字段类型都有一个合适的默认Widget 类,需要时可以覆盖。

 

widget 部件

实例化、处理和渲染表单

在Django 中渲染一个对象时,我们通常:

  1. 在视图中获得它(例如,从数据库中获取)
  2. 将它传递给模板上下文
  3. 使用模板变量将它扩展为HTML 标记

在模板中渲染表单和渲染其它类型的对象几乎一样,除了几个关键的差别。

 

构建一个表单

在html里构建这里就不写了

1.在app下面新建一个存放Forn类的文件

例如:myforms.py

  

#!/usr/bin/env python#-*- coding:utf-8 -*-from django import formsfrom django.forms import  fieldsclass UserForm(forms.Form):    user = fields.CharField(        max_length=18,        min_length=6,        required = True,        error_messages={            ‘required‘:‘用户输入为空‘,            ‘max_length‘:‘用户输入太长了‘,             ‘min_length‘:‘用户输入太短了‘        })    #自定义错误显示信息    pwd = fields.CharField(required=True,min_length=8)    age = fields.IntegerField(required=True)    email = fields.EmailField(required=True,min_length=8,                              error_messages={                                  ‘invalid‘:"用户输入格式错误,只要是格式错误都用invalid"                              })

  

  

注:它不包含 <form> 标签和提交按钮。我们必须自己在模板中提供它们。

要操作一个通过URL发布的表单,我们要在视图中实例表单。

2.views.py

from django.shortcuts import renderfrom django.shortcuts import redirectfrom app01.myfoms import UserForm# Create your views here.def users(request):    if request.method == "GET":        obj = UserForm()  #这就相当于自动生成了一个html        return render(request,‘fm.html‘,{‘obj‘:obj})    elif request.method == ‘POST‘:        fo = UserForm(request.POST)        # print(fo)  #前端提交过来的数据        v = fo.is_valid()  # 判断发过来的数据验证是否通过        if v:            print(fo.cleaned_data)  # 查看用户提交的数据            return redirect(‘http://www.baidu.com‘)  # 成功验证跳转到百度        else:            print(fo.errors)  # 查看相应提交数据的错误信息            return render(request, ‘fm.html‘, {"obj": fo})    return render(request, ‘fm.html‘)

  

3.url

from django.conf.urls import urlfrom django.contrib import adminfrom app01 import viewsurlpatterns = [    url(r‘^admin/‘, admin.site.urls),    url(r‘^users/$‘, views.users),]

  

4.模板html

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body><form action="/users/" method="POST" novalidate>    <p>{{ obj.user }}{{ obj.errors.user.0 }} </p>    <p>{{ obj.pwd }}{{ obj.errors.pwd.0 }}</p>    <p>{{ obj.age }}{{ obj.errors.age.0 }}</p>    <p>{{ obj.email }}{{ obj.errors.email.0 }}</p>    <input type="submit" value="http://www.mamicode.com/提交"></form>/* obj.error.user.0 是显示在输入框后显示错误的显示信息  */</body></html>

  

提示:

form类实例化的方法和属性is_valid() 方法     判断表单提交是否合法的数据结构,返回True/Falsecleaned_data    属性中找到所有合法的表单数据  转换好为Python 的字典类型。

 

 

 

使用表单模板

 

例如:

1新建一个表单的py文件 例如:myForms.py  在app下面新建表单内容,

内容如下

#!/usr/bin/env python#-*- coding:utf-8 -*-from django import formsfrom django.forms import  fieldsclass UserInfo(forms.Form):    user = fields.CharField()    age = fields.IntegerField()

  

2.视图views.py

from django.shortcuts import renderfrom app01 import  myForms# Create your views here.def index(request):    form = myForms.UserInfo()    if request.method == ‘GET‘:        return render(request,‘index.html‘,{‘form‘:form})

  

3.路由urls.py

from django.conf.urls import urlfrom django.contrib import adminfrom app01 import  viewsurlpatterns = [    url(r‘^admin/‘, admin.site.urls),    url(r‘^index/‘, views.index),]

  

4.模板html

通过视图把fom表单渲染到模板的html

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body><form action="/index" method="POST">    <table border="1">{{ form.as_table }}</table>    {{ form.as_p }}    <ul>        {{ form.as_ul }}    </ul></form></body></html>

  

上面用了几个表单渲染,form.as_p  和 forms.as_ul  和 forms.as_table

表单渲染选项

表单模板的额外标签
不要忘记,表单的输出不 包含<form> 标签,和表单的submit 按钮
对于<label>/<input> 对,还有几个输出选项:

 

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

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

 表单字段详解

在django的form表单api,每个字段都是一个类,所有的字段都继承Field这个类。
提示:多看源码

Field这个类的常用参数

Field    required=True,               是否允许为空    widget=None,                 HTML插件  注:重点    label=None,                  用于生成Label标签或显示内容  类似HTML的label的标签    initial=None,                初始值	  (<input type="text" value="http://www.mamicode.com/xixi"> 类似html的input框的value值)    help_text=‘‘,                帮助信息(在标签旁边显示)    error_messages=None,         错误信息 {‘required‘: ‘不能为空‘, ‘invalid‘: ‘格式错误‘}    show_hidden_initial=False,   是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)    validators=[],               自定义验证规则    localize=False,              是否支持本地化    disabled=False,              是否可以编辑    label_suffix=None            Label内容后缀  

  

常用字段

ChoiceField   选择类型的字段(例如,下拉框,等等)	choice[(1,‘北京‘),(2,‘上海‘),(3,‘深圳‘)]   这个选项是提供下拉框的内容		表单模板的额外标签	不要忘记,表单的输出不 包含<form> 标签,和表单的submit 按钮	对于<label>/<input> 对,还有几个输出选项:	{{ form.as_table }} 以表格的形式将它们渲染在<tr> 标签中	{{ form.as_p }}  将它们渲染在<p> 标签中	{{ form.as_ul }} 将它们渲染在<li> 标签中	注意,你必须自己提供<table> 或<ul> 元素。	CharField(Field)    max_length=None,             最大长度    min_length=None,             最小长度    strip=True                   是否移除用户输入空白IntegerField(Field)    max_value=http://www.mamicode.com/None,              最大值"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=‘‘,              帮助提示注:choices选项:由可迭代的二元组组成(比如[(A, B), (A, B) ...]),用来给这个字段提供选择项。如果设置了 choices ,默认表格样式就会显示选择框,而不是标准的文本框,而且这个选择框的选项就是 choices 中的元组。 每个元组中的第一个元素,是存储在数据库中的值;第二个元素是该选项更易理解的描述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= http://www.mamicode.com/‘‘            空值的默认值>

  

重点form字段

Form重点:    - 字段        用于保存正则表达式        ChoiceField *****        MultipleChoiceField        CharField        IntegerField        DecimalField        DateField        DateTimeField        EmailField        GenericIPAddressField        FileField                RegexField

  

表单字段的HTML插件

所有Field字段本质上封装了两个东西,一个是正则表达式,一个是HTML插件

每个表单字段都有一个对应的Widget 类,它对应一个HTML 表单Widget,例如<input type="text">。

在大部分情况下,字段都具有一个合理的默认Widget。例如,默认情况下,CharField 具有一个TextInput Widget,它在HTML 中生成一个<input type="text">。

 

Django内置插件

TextInput(Input)NumberInput(TextInput)EmailInput(TextInput)URLInput(TextInput)PasswordInput(TextInput)HiddenInput(TextInput)Textarea(Widget)DateInput(DateTimeBaseInput)DateTimeInput(DateTimeBaseInput)TimeInput(DateTimeBaseInput)CheckboxInputSelectNullBooleanSelectSelectMultipleRadioSelectCheckboxSelectMultipleFileInputClearableFileInputMultipleHiddenInputSplitDateTimeWidgetSplitHiddenDateTimeWidgetSelectDateWidget

  

常用widget的选择HTML插件

 不要将Widget 与表单字段搞混淆。表单字段负责验证输入并直接在模板中使用。Widget 负责渲染网页上HTML 表单的输入元素和提取提交的原始数据。但是,Widget 需要赋值给表单字段。

 

# 单radio,值为字符串  widgets方式# user = fields.CharField(#     initial=2,#     widget=widgets.RadioSelect(choices=((1,‘上海‘),(2,‘北京‘),))# ) # 单radio,值为字符串    ChoiceField选择字段方式# 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# )

  

提示:根据自已喜好,选择用widget插件,还是ChoiceField方式

 widget只能生成form相关的html标签,不能生成div,span标签等等。。。。

数据实时更新

方式一:(推荐)

在使用选择标签时,需要注意choices的选项可以从数据库中获取,但是由于是类属性字段 ***获取的值无法实时更新***,

那么需要自定义构造方法(__init__)从而达到此目的。

 

from django.forms import Formfrom django.forms import widgetsfrom django.forms import fieldsclass 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‘)

  

 

方式二:

依赖数据库的model的__str__方法 

from django import formsfrom django.forms import fieldsfrom django.forms import widgetsfrom django.forms.models import ModelChoiceField class FInfo(forms.Form):    authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())    # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())    to_field_name=‘id‘  #使用id的那列字段作为input框的value值

  

 FORM自定制匹配正则表达式的扩展

方式一

  

from django.forms import Formfrom django.forms import widgetsfrom django.forms import fieldsfrom django.core.validators import RegexValidator                 class MyForm(Form):       user = fields.CharField(       error_messages={‘invalid‘: ‘...‘},       validators=[RegexValidator(r‘^[0-9]+$‘, ‘请输入数字‘), RegexValidator(r‘^159[0-9]+$‘, ‘数字必须以159开头‘)],                    )

  

字段下的validator

validators=[RegexValidator(r‘^[0-9]+$‘, ‘请输入数字‘)] 
validators 自定义匹配正则表达式,可以有多个匹配的正则表达式,匹配顺序是从前到后
RegexValidator这个类有两个参数,第一个是正则表达式,第二个错误提示

 

方式二

from django.forms import Formfrom django.forms import widgetsfrom django.forms import fieldsfrom django.core.validators import RegexValidator                 class MyForm(Form):      user = fields.RegexField(r‘^[0-9]+$‘,error_messages={‘invalid‘: ‘...‘})                    

  

正则字段

 

基于源码流程的扩展

如果某一个字段不仅只是自定义正则表达式匹配,例如:还有一些用户注册的唯一性等等要求,这时候就要基于form源码来扩展

单子段验证

重写:clean_字段名方法

from django import formsfrom django.forms import fieldsfrom django.forms import widgetsfrom django.core.exceptions import NON_FIELD_ERRORS, ValidationErrorclass AForm(forms.Form):       username = fields.CharField()       user_id = fields.IntegerField(                    widget=widgets.Select(choices=[(0,‘张三‘),(1,‘李四‘),(2,‘老王‘),])                )            # 自定义方法 clean_字段名            # 必须返回值self.cleaned_data[‘username‘]            # 如果出错:raise ValidationError(‘用户名已存在‘)       def clean_username(self):                v = self.cleaned_data[‘username‘]                if models.UserInfo.objects.filter(username=v).count():                    # 整体错了                    # 自己详细错误信息                    raise ValidationError(‘用户名已存在‘)                return v       def clean_user_id(self):               return self.cleaned_data[‘user_id‘]

  

整体错误验证

自定义clean方法

            class AForm(forms.Form):                username = fields.CharField()                user_id = fields.IntegerField(                    widget=widgets.Select(choices=[(0,‘张三‘),(1,‘李四‘),(2,‘老王‘),])                )                # 自定义方法 clean_字段名                # 必须返回值self.cleaned_data[‘username‘]                # 如果出错:raise ValidationError(‘用户名已存在‘)                def clean_username(self):                    v = self.cleaned_data[‘username‘]                    if models.UserInfo.objects.filter(username=v).count():                        # 整体错了                        # 自己详细错误信息                        raise ValidationError(‘用户名已存在‘)                    return v                def clean_user_id(self):                    return self.cleaned_data[‘user_id‘]                def clean(self):                    value_dict = self.cleaned_data                    v1 = value_dict.get(‘username‘)                    v2 = value_dict.get(‘user_id‘)                    if v1 == ‘root‘ and v2==1:                        raise ValidationError(‘整体错误信息‘)                    return self.cleaned_data

  

 

haha