Python-Web---表单

一.Django框架之MTV

Python-Web---表单_第1张图片

项目启动后,用户通过浏览器向Web服务器发起请求,Web服务器将请求传递到要处理该请求的Django项目,Django接收用户通过浏览器发起的请求,urls.py文件根据URL地址分发路由,将请求交给views.py中相应的视图;视图处理请求(此时涉及数据存取),并将处理结果与模板结合生成响应数据返回给Web服务器,服务器将数据返回到浏览器,最终呈现给用户。

Django使用MTV架构,该架构由模型(Model)、模板(Template)、视图(View)三部分组成,各部分的职责如下。

  • 1.  模型:数据操作层,定义数据模型,封装对数据库层的访问。
  • 2.  模板:表现层,负责将页面呈现给用户。
  • 3.  视图:业务逻辑层,调用模型和模板,实现业务逻辑。 

Django项目的数据模型定义在模型文件models.py中,模板文件存储在templates目录(需手动创建与配置)中,业务逻辑存储在视图文件views.py中。此外Django项目还有一个核心文件urls.py,用于实现路由分发功能。

二.HTML表单

一个典型的HTML表单如下




    
    
    静态表格


    

该表单由静态HTML实现,要直接在浏览器中访问该表单,需将其放在Django项目的static静态资源文件夹中。

Python-Web---表单_第2张图片

1.静态配置内容:

第一步:新建项目文件chapter01,在项目中创建新的应用。

django-admin startproject chapter01
python manage.py app

第二步:在settings.py注册app,配置文件夹templates的路径,以及数据库mysql

#templates路径
'DIRS': [os.path.join(BASE_DIR, 'templates')],

#mysql数据库
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'test',
        'HOST':'localhost',
        'PORT': 3306,
        'USER':'root',
        'PASSWORD':'myy040715'
        }
}

在settings.py中,默认静态资源URL访问路径配置:

STATIC_URL = '/static/' 

 第四步:app中创建文件夹:static

 第五步:将照片放在static文件夹中

第六步:测试:http:127.0.0.1:8000/static/pic.png

Python-Web---表单_第3张图片

 第七步:在static文件夹下创建静态文件(表格.html)




    
    
    静态表格


    

 测试(http://127.0.0.1:8000/static/表格.html):静态表格

 Python-Web---表单_第4张图片

2.共享静态文件

根目录下创建public_statics文件夹(与应用app同级)

在settings.py中配置

STATICFILE_DIRS=[os.path.join(BASE_DIR,'public_statics'),]
3.HTML模板文件

创建静态文件(htmlform.html)




    
    
    Document


    
{% csrf_token %}

计算得到的值是:{{number}}

定义视图函数(views.py)

from django.shortcuts import render

# Create your views here.

def getdata(request):
    data=''
    number=''
    if 'data' in request.POST:
        data=request.POST['data']
        number = data * 2
    return render(request,'htmlform.html',{'current_data':data,'number':number})

配置根路由(urls.py)

from django.contrib import admin
from django.urls import path,include
urlpatterns = [
    path('admin/', admin.site.urls),
    path('',include('app.urls')),
]

配置子路由: 

from django.contrib import admin
from django.urls import path
from app import views

urlpatterns = [
    path('getdata/',views.getdata),
]

Python-Web---表单_第5张图片Python-Web---表单_第6张图片

三.Django表单 

模板中的HTML表单中,要改变表单就必须修改模板文件。 Django表单通过扩展django.forms.Form类可在视图中动态生成表单。

1.定义表单类
  • 自定义的表单类dataForm继承了django.forms.Form类,它包含一个data字段。
  • 字段data的类型为forms.CharField。 表单data字段会被渲染为一个
  • 表单字段的label参数指定在表单渲染生成的

定义视图函数(views.py)

from django import forms
class dataForm(forms.Form):
    data = forms.CharField(label='请输入数据')

#使用表单类和视图
def useDataForm(request):
    if request.method == 'POST':
        form = dataForm(request.POST)
        msg='数据已提交'
    else:
        form = dataForm()
        msg = '初始表单'
    return render(request,'temdataform.html',{'form':form,'msg':msg})
  • 在直接使用HTML表单时,视图将数据传递给模板,以便在响应页面中回显数据。
  • 在使用Django表单时,视图使用接收到的数据创建表单,先将数据填入表单字段,再将表单对象传递给模板。 

创建模板文件(temdataform.html) 




    
    
    Document


    
{% csrf_token %} {{form}}
{{msg}}

配置子路由(urls.py)

path('dform/',views.useDataForm),

Python-Web---表单_第7张图片Python-Web---表单_第8张图片

 2.表单字段渲染方式
  • {{ form.as_table }}:表单式样式,默认方式。将字段渲染为包装在表格元素中的表单元素。
  • {{ form.as_p }}:段落样式,将字段渲染为包装在

    元素中的段落。

  • {{ form.as_ul }}:列表样式,将字段渲染为包装在
  • 元素中的列表项。

配置视图函数(views.py)

def useDataForm3(request):
    return render (request,'temdataform3.html',{'form':dataForm()})

 创建模板文件(temdataform3.html)




    
    
    Document


    表格样式渲染的结果:
    
{%csrf_token%} {{form.as_table}}

段落样式渲染的表单
{%csrf_token%} {{form.as_p}}

列表样式渲染的表单
{%csrf_token%}
    {{form.as_ul}}

配置子路由(urls.py)

path('dform3/',views.useDataForm3),

Python-Web---表单_第9张图片

3.表单字段类型和参数

表单字段定义包含字段名、字段类型和字段参数3个部分 、

class dataForm(forms.Form):    

data = forms.CharField(label='请输入数据')    #定义表单字段

data为字段名,字段渲染生成的

定义视图函数(views.py) 

class dataForm2(forms.Form):
    data = forms.CharField(label='请输入数据',)
    a = forms.BooleanField(label='a')
    sex = forms.ChoiceField(label='sex')
    date = forms.DateField(label='date')

def useDataForm4(request):
    return render (request,'temdataform4.html',{'form':dataForm2()})

创建模板文件(temdataform4.html) 




    
    
    Document


    
{%csrf_token%} {{form}}
{{msg}}

配置子路由(urls.py) 

path('dform4',views.useDataForm4),

Python-Web---表单_第10张图片

 4.常用表单字段类
Python-Web---表单_第11张图片
Python-Web---表单_第12张图片 (1).required

参数required用于设置当前字段是否为必需字段。

  • 默认情况下,所有类型的表单字段的required属性值均为True。如果提供的是None或空字符串,校验数据时会触发ValidationError异常。
  • 表单字段的clean()方法用于执行数据清理操作,验证数据的有效性。数据有效时,clean()方法会返回该数据,否则触发ValidationError异常。
#在终端里运行
python manage.py shell
from django import forms
name=forms.CharField()
name.clean('') #报错
name.clean(' ')     #报错
name.clean(None)     #报错
name.clean(0)
name.clean(True)
name.clean(False)
name.clean(123)
name.clean('as')

 Python-Web---表单_第13张图片

(2).label 

label参数用于设置表单字段被渲染为HTML

class test(forms.Form):
...     name=forms.CharField(label='请输入姓名')
... 
>>> print(test())

#在创建表单时,可使用auto_id=False来简化渲染结果
d=test(auto_id=False)
print(d)

 

(3).label_suffix 

label_suffix属性用于设置表单字段被渲染为HTML

>>> class test(forms.Form):
...     addr=forms.CharField(label='联系地址',label_suffix='*')
... 
>>> print(test())

(4).initial 
#initial参数用于设置字段的初始值
>>> class test(forms.Form):
...      name=forms.CharField(initial='someone')
... 
>>> print(test(auto_id=False))


#也可在创建表单对象时提供初始值:
>>> d=test({'name':'Lining'},auto_id=False)
>>> print(d)

Python-Web---表单_第14张图片 

 (5).help_text

help_text参数用于设置字段的帮助信息,帮助信息被渲染为元素

class test(forms.Form):
...     name=forms.CharField(help_text='姓名包含字母、数字等字符')  
...
>>> print(test(auto_id=False))

(5).error_messages 
  • error_messages用于设置自定义错误信息,它将覆盖默认的错误信息。
  • error_messages的参数值为字典对象,其中的每个键值对对应一条校验错误信息
name=forms.CharField(error_messages={'required':'必须提供name字段数据'})
name.clean('11')

(6).disabled 

disabled参数被设置为True时,不允许表单字段渲染成的HTML元素与用户交互

class test(forms.Form):
...     addr=forms.CharField(label='联系地址',disabled=True)
...
>>> print(test())

 5.Form类的字段校验

表单验证即对表单中的数据进行验证,检验表单各个字段的数据是否符合该字段的约束条件。通常,Django根据字段类型执行默认的校验操作。

Django类字段常见验证操作

Python-Web---表单_第15张图片

下面定义一个validate_lt()函数,它在字符串包含小于或大于符号时抛出ValidationError异常。

>>> from django.core.exceptions import ValidationError
>>> def validata_lt(value):
...    if"<" in value or ">" in value:
...        raise ValidationError("不允许小于号或大于号")
...
>>> str=forms.CharField(validators=[validata_lt])   #定义字段,引用自定义异常函数
>>> str.clean("1<99")

#校验函数内,出现不符合校验标准的情况必须抛出ValidationError异常,异常信息作为校验错误的提示信息

Python-Web---表单_第16张图片

6.Django中的Form模块

request.POST包含了表单采用POST请求方法提交数据,可以使用表单校验传过来的数据是否合法,还能将校验的错误信息保存,还可以判断forms有没有绑定相关的数据。

(1).使用表单数据
  • request.POST包含了表单采用POST请求方法提交的数据。
  • request.POST中的数据没有被转换为Python类型,也没有经过校验。 表单通过校验时,is_valid()函数返回True。
  • 表单中通过校验的数据被包含在cleaned_data字典中。
  • 在使用表单数据时,应尽量使用cleaned_data中的数据.
#设置了数据的表单称为绑定表单(is_bound属性为True),没有数据的表单称为未绑定表单(is_bound属性为False)。
>>> class test(forms.Form): 
...   name=forms.CharField(max_length=50)
...   age=forms.IntegerField(max_value=50)
...
>>> d=test()						#创建空表单
>>> d.is_bound						#结果为False,说明表单未绑定

>>> d=test({})						#绑定空值时,表单也被绑定
>>> d.is_bound						#结果为True,说明表单已绑定

>>> d=test({'name':'mike','age':20})	#绑定具体数据
>>> d.is_bound

Python-Web---表单_第17张图片

(2).使用Form校验数据

调用表单is_valid()方法时会执行数据校验,当所有字段数据均合法时,方法返回True,否则返回False。

#打开python manage.py shell的时候,都要导入表单。
>>> from django import forms
class test(forms.Form):
...     age=forms.IntegerField(max_value=35)
...     name=forms.CharField(max_length=20)
... 
>>> d=test({'name':'zhangsan','age':20})     #绑定具体数值
>>> d.is_valid()                              #字段数据符合form标单参数要求,通过校验

>>> d=test({'name':'xiaoming','age':36})
>>> d.is_valid()

Python-Web---表单_第18张图片

执行校验时,Django为表单对象创建cleaned_data属性。 通过校验的数据是“干净的”,被保存在表单的cleaned_data属性中。 cleaned_data属性只能在执行校验之后访问,否则会触AttributeError异常。

>>> d=test({'name':'xiaoming','age':20}) 
>>> d.cleaned_data    #触发异常
>>> d.is_valid()
True
>>> d.cleaned_data
{'age': 20, 'name': 'xiaoming'}
>>>

Python-Web---表单_第19张图片

如果有数据没有通过校验,is_valid()方法返回Flase,cleaned_data属性中保存了已经通过校验的字段数据,error属性保存未通过校验的字段的错误信息。

>>> d=test({'name':'zhangsan','age':50}) 
>>> d.is_valid()   

>>> d.cleaned_data

Python-Web---表单_第20张图片

  • From.errors:它是一个类属性,保存的是校验错误信息。

  • errors返回一个字典对象,其中的每个键值对中的键是字段名,值是一个列表对象,列表对象包含错误信息字符串。可以调用as_json()或get_json_data()方法返回包含JSON格式的错误信息。
>>> d.errors.as_json()
>>> d.errors.get_json_data()
 (3).使用FRom表单输出

Form对象的另一个作用是将自身转为HTML。为此,我们只需要简单的使用print()方法可以看到From对象的HTML输出。

class test(forms.Form):
...     age=forms.IntegerField(max_value=35) 
...     name=forms.CharField(max_length=20)
...
>>> print(test())

如果表单绑定了数据,则HTML输出包含数据的HTML文本。 

d=test({'name':'zhangsan','age':50})
>>> print(d)
 7.手动处理表单字段

手动处理表单字段时可将每个表单字段视为表单属性,通过{{form.name_of_field}}的形式访问。Django允许在表单模板中自定义表单字段的渲染效果。在模板中,用{{form.字段名}}格式来访问表单字段。在表单模板中,也可用{%for%}循环来遍历表单字段。表单字段的常用属性如下。

  • {{ form.字段名.label }}:字段的label文本,例如,“姓名”。
  • {{ form.字段名.label_tag }}:封装在HTML
  • {{ form.字段名.value }}:字段值。
  • {{ form.字段名.help_text }}:字段的帮助文本。
  • {{ form.字段名.errors }}:字段未通过验证时的错误信息。
  • {{ form.字段名.field }}:表单字段的 BoundField实例对象,用于访问字段属性。例如, {{ form.name.field.max_length }} 。

相比较Django对表单字段的自动解析,手动处理更加灵活,开发者可以有选择的处理字段,也可以调整字段顺序。下面定义成绩表单的例子

定义视图函数(views.py)

class test(forms.Form):
    name=forms.CharField(max_length=50,label='姓名')
    age=forms.IntegerField(max_value=50,min_value=15,label="年龄",help_text='年龄小于15且不大于50')

def useTest(request):
    if request.method == 'POST':
        form = test(request.POST)
    else:
        form = test()
    return render(request, 'temtest.html', {'form': form})

创建模板文件(temtest.html)




    
    
    Document


    
{% csrf_token %}
{{form.name.label}}={{form.name}}
{{form.age.label}}={{form.age}}{{form.age.help_text}}

 配置子路由:

path('diyfield/',views.useTest),

Python-Web---表单_第21张图片

Python-Web---表单_第22张图片

 8.遍历表单字段

在表单模板中,若每个表单字段使用相同的HTML,也可用{%for%}循环来遍历表单字段。

在templates里面创建模板文件(temtestfor.html)




    
    
    Document


    

遍历表单字段

{%csrf_token%} {%for field in form%}

{{field.error}} {{field.label_tag}} {{field}} {%if field.help_text%} {{field.help_text|safe}} {%endif%}

{%endfor%}

定义视图函数(views.py)

def useTestFor(request):
    return render (request,'temtestfor.html',{'form':test()})

配置子路由: 

path('diyfor/',views.useTestFor),

Python-Web---表单_第23张图片Python-Web---表单_第24张图片 

 四.表单集

表单集是表单对象的集合,用于处理多个表单。利用表单集,用户可以同时提交一组表单,在数据库中添加多条记录。

1.创建表单集

可调用django.forms模块提供的formset_factory()工厂类方法创建表单集类,定义视图(views.py)

#创建表单集
class GoodForm(forms.Form):
    name = forms.CharField(label='商品')
    price = forms.DecimalField(label='价格')
    stock = forms.IntegerField(label='库存')
    sales = forms.IntegerField(label='销量')

from django.forms import formset_factory
from django.shortcuts import render

def useFormset(request):
    classTestFormset = formset_factory(GoodForm, extra=2)
    if request.method == 'POST':
        formset = classTestFormset(request.POST)
    else:
        formset = classTestFormset()
    return render(request, 'temformset.html', {'formset': formset})

创建模板文件(temformset.html)




	
	商品表单集合


	

商品表单集合

{% csrf_token %} {{ formset.management_form }} {% for form in formset.forms %} {{ form.as_p }} {% endfor %}

配置子路由(app里面urls.py)

path('formset/',views.useFormset),

Python-Web---表单_第25张图片

表单集中的表单分为空表单和非空表单,表单集中空表单的数量默认为1。在页面中查看渲染得到的HTML代码可以发现,代码输出结果中只有一个空表单,这是因为表单集默认只显示一个表单,另外表单集中的表单尚未绑定数据。

如以下可知:extra可以控制表单集中空表单的数量,默认值为1,

Python-Web---表单_第26张图片

设置表单集的初始数据(initial)

像表单一样,以上代码使用initial参数为表单集设置了初始值。由于initial参数接收的字典中只有一个元素, 所以表单集中包含 了一个绑定了初始值的表单和两个空表单。

Python-Web---表单_第27张图片Python-Web---表单_第28张图片 

 限制表单的最大数量

利用参数max_num可以控制表单集中表的表单数量。max_num设置为None,那么表单最多包含1000张表单。

Python-Web---表单_第29张图片

 五.根据模型创建表单

  • 模型表单指绑定到模型的表单。自定义的模型表单需扩展django.forms模块提供的ModelForm类。
  • 模型表单基本操作包括定义模型、定义模型表单以及使用模型表单为数据库添加和修改数据。

定义模型(models.py):

from django.db import models

class person(models.Model):
    name=models.CharField(max_length=8)
    age=models.SmallIntegerField()

生成迁移文件,执行数据的迁移

python manage.py makemigrations
python manage.py migrate

模型表单有两个特点:

  • 必须继承django.forms.ModelForm类。
  • 提供子类Meta。在Meta的model字段中绑定模型,在fields字段中设置在表单中使用的模型字段。
  • 可以使用特殊值“__all__”表示使用模型全部字段,示例代码如下。 fields = '__all__'
  • 也可使用exclude属性来排除不使用的字段,示例代码如下。 exclude = ['age']

定义视图函数(views.py):

#模型表单
from .models import person
from django.forms import ModelForm

class personForm(ModelForm):
    class Meta:
        model = person
        fields = '__all__'

def usePersonForm(request):
    if request.method == 'POST':
        mform = personForm(request.POST)
        if mform.is_valid():
            ps=person.objects.filter(name=request.POST['name'])
            if ps.count()==0:
                mform.save()
                msg='数据已保存!'
            else:
                msg='数据库已存在相同姓名的数据,请勿重复提交!'
        else:
            msg='表单数据有错'
    else:
        mform = personForm()
        msg="请输入数据添加新纪录"
    return render(request,'temmodelform.html',{'mform':mform,'msg':msg})

视图在使用POST请求时,视图通过request.POST 获得客户端提交的数据。将requestPOST作为参数初始化表单,执行表单验证操作,可以检查数据是否有效。在数据有效时,用客户端提交的书名作为条件执行查询。当数据库中不存在相同姓名时,执行表单保存操作,将数据写入数据库。

创建模板文件(temmodelform.html)




    
    
    Document


    
{%csrf_token%} {{mform}}

{{msg}}

配置子路由(urls.py)

path('mform/',views.usePersonForm),

Python-Web---表单_第30张图片 Python-Web---表单_第31张图片

Python-Web---表单_第32张图片
六.自定义模型表单字段

通常情况下,模型表单字段与模型字段保持一致。 Django允许在模型表单中覆盖模型字段定义

定义模型(views.py)

#自定义模型表单字段
from django.forms import ValidationError

def validate_age(value):
    if int(value) < 20:
        raise ValidationError('年龄不能小于20!',code='min_value')
    elif int(value) >50:
        raise ValidationError('年龄不能大于50!',code='max_value')
    
class personFormDIY(ModelForm):
    #重定义age字段
    age=forms.CharField(validators=[validate_age],label='年龄',\
                        widget=forms.NumberInput(),\
                        help_text= '年龄为[20,50]以内的整数')
    class Meta:
        model=person 
        fields = ['name','age']
        labels = {'name':'姓名'}
        help_texts ={'name':'姓名为中英文字符串',}
        widgets = {'name' : forms.Textarea(attrs={'cols':30,'rows':2}),}

def usePersonFormDIY(request):
    if request.method == 'POST':
        mform = personFormDIY(request.POST)
        if mform.is_valid():
            ps=person.objects.filter(name=request.POST['name'])
            if ps.count()==0:
                mform.save()
                msg='数据已保存!'
            else:
                msg='数据库已存在相同姓名的数据,请勿重复提交!'
        else:
            msg='表单数据有错'
    else:
        mform = personForm()
        msg="请输入数据添加新纪录"
    return render(request,'temmodelformdiy.html',{'mform':mform,'msg':msg})

创建模板文件(temmodelformdiy.html)




    
    
    Document


    
{%csrf_token%} {{mform.as_p}}

{{msg}}

配置子路由:

path('mdiy/',views.usePersonFormDIY)

 Python-Web---表单_第33张图片Python-Web---表单_第34张图片

 七.表单样式优化

1.资源

资源指应用于表单的CSS和JavaScript文件。

当定义表单或小部件时,可以在Media子类中为其定义资源。在渲染表单时,Django会将资源文件包含到HTML中。

2.小部件资源

通过扩展小部件定义表单资源的基本格式如下。 class 自定义小部件类名称(forms.内置小部件类名称):    

class Media:          

css={'设备类型': ('CSS资源文件URL',……),……}          

js= ('JavaScript资源文件URL',……)

Media子类的css属性用于设置CSS资源。css属性中的键设置CSS资源中的样式单适用的设备类型 资源文件的URL可以使用相对路径或绝对路径。CSS和JavaScript资源文件属于静态资源,通常将其放在项目的static文件夹中

 可用的类型名称如下。

  • all:默认。适用于所有设备。
  • aural:语音合成器。
  • braille:盲文反馈装置。
  • handheld:手持设备。
  • projection:投影仪。
  • print:打印预览模式或打印页面。
  • screen:计算机屏幕。
  • tty:电传打字机以及类似的使用等宽字符网格的设备。
  • tv:电视机类型设备。

以图6-17的自定义的模型表单bookformly为例,通过css静态文件优化表单样式

第一步:在项目同名文件夹下创建static文件夹,将css样式单文件diyform.css放入static文件夹内

Python-Web---表单_第35张图片

.helptext{
    color:cadetblue;
    font-size:12px;
}
.errorlist{
    color:red;
    font-size: 12px;
}
p{
    color: darkgoldenrod;
    font-size: 18px;
}
body{
    background: url(./pic1.jpg) no-repeat center center fixed;
    background-size: cover;
    padding-top: 20px;
}
form {
    width: 543px;
    height: 300px;
    margin: 0 auto;
    padding: 20px;
    border: 1px solid rgba(0,0,0,0.2);
    border-radius: 5px;
    background: rgba(0,0,0,0.5);
    overflow: hidden;
}
input{
    width: 96px;
    height: 28px;
    border: 1px solid rgba(255,255,255,0.4);
    border-radius: 4px;
    display: inline-block;
    font-size: 16px;
    color: #fff;
    background: rgba(255,255,255,0.4) no-repeat 16px 16px;
    margin-bottom: 10px;
    padding-left: 25px;
    padding-right: 20px;
}

修改temmodelformdiy.html,添加{{bform.media}}变量,以及css的链接路径




    
    
    Document
    


    {{bform.media}}
    
{%csrf_token%} {{mform.as_p}}

{{msg}}

 Python-Web---表单_第36张图片 

你可能感兴趣的:(python,开发语言)