Dajngo学习
基础表单django.forms.Form
表单介绍
HTML表单负责接收用户的输入,对输入进行合法格式判断,并将数据发送到服务器。一个HTML表单必须指定两样东西:发送数据的url地址,发送的HTTP方法(GET、POST)。
类型 | 说明 |
---|---|
GET方法 | 将用户数据以?<键1>=<值1>&<键2>=<值2>&…形式拼接到url后面,通常用于请求数据、网页搜索的表单。 |
POST方法 | 组合表单的数据并进行编码,然后打包发送到服务器,数据不会出现在url中,通常用于保密信息的发送、大量数据的表单、二进制数据。 |
表单是搜集用户数据信息,实现网页数据交互的关键。Django的表单功能由Form类实现,主要分两种:django.forms.Form和django.forms.ModelForm。前者是一个基础的表单功能,后者是在前者的基础上结合模型所生成的数据表单。
虽然在模板文件中直接编写表单是一种较为简单的实现方法,但如果表单元素较多,会在无形之中增加模板的代码量,对日后维护和更新造成极大的不便。为了简化表单的实现过程和提高表单的灵活性,Django提供了完善的表单功能。先来看个简单的例子。
在mysite的index中添加一个form.py用于编写表单的实现功能,然后在templates文件夹中添加模板data_form.html,用于将表单数据显示到网页上。在input标签中
对于form表单也是一样,如果前端不指定post方法,默认使用get方法。
首先在form.py中添加以下代码:
#index 的 form.py
from django import forms
from .models import *
class ProductForm(forms.Form):
name = forms.CharField(max_length=20, label='名字')
weight = forms.CharField(max_length=50, label='重量')
size = forms.CharField(max_length=50, label='尺寸')
#设置下拉框的值
## choices_list = [(1,'手机'),(2, '平板')]
choices_list = [(i+1, v['type_name']) for i,v in enumerate(Type.objects.values('type_name'))]
type = forms.ChoiceField(choices=choices_list, label='产品类型')
在form.py中定义表单类ProductForm,类属性就是表单字段,对应HTML里的每一个控件。
然后在视图函数中导入form.py所定义的ProductForm类,在index函数中实例化生成对象,再将对象传递给模板文件。
#index 的 views.py
from django.shortcuts import render
from .form import *
def index(request):
product = ProductForm()
return render(request, 'data_form.html', locals())
最后在模板文件data_form.html中将对象product以HTML的
的形式展现在网页上
//templates 下的 data_form.html
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" method="post">
<table>
{{ product.as_table }}
</table>
<input type="submit" value="提交">
</form>
</body>
</html>
表单字段(常用)
- CharField
渲染类型:TextInput
输入空值的返回:empty_value设定的值
转换为对象:Unicode对象
验证:min_length,max_length(如果设置过)
可用的错误信息键:min_length,max_length,required
max_length:允许输入的最大长度
min_length:允许输入的最小长度
strip:默认为True,表示去除前后的空格
empty_value:输入为空时返回的值,默认为空字符串
- EmailField
渲染类型:EmailInput
输入空值的返回:空字符串
转换为对象:Unicode对象
验证:用正则表达式验证表单的值,必须是合法邮件地址
可用的错误信息键:required,invalid
max_length:允许输入的最大长度
min_length:允许输入的最小长度
- 更多
字段 | 说明 |
---|---|
BooleanField | 复选框,如果字段带有initial=True, 复选框被勾上 |
CharField | 文本框,参数max_length和min_length |
ChoiceField | 下拉框,参数choices设置数据内容 |
TypedChoiceField | 与ChoiceField相似,但多出参数coerce和empty_value,分别代表强制转换数据类型和用于表示空值,默认为空字符串 |
DateField | 文本框,具有验证日期格式的功能,参数input_formats设置日期格式 |
EmailField | 文本框,验证输入数据是否符合邮箱格式,可选参数max_length和min_length |
FileField | 文件上传功能,参数max_length和allow_empty_file分别设置最大长度和文件内容是否为空 |
FilePathField | 在特定的目录选择并上传文件,参数path是必需参数,参数recursive、match、allow_files和allow_folders为可选参数 |
FloatField | 验证数据是否为浮点数 |
ImageField | 验证文件是否为Pillow库可识别的图像格式 |
IntegerField | 验证数据是否为整型 |
GenericIPAddressField | 验证数据是否为有效数值 |
SlugField | 验证数据是否只包含字母、数字、下划线及连字符 |
TimeField | 验证数据是否为datetime.time或指定特定时间格式的字符串 |
URLField | 验证数据是否为有效的URL地址 |
表单字段的参数
error_messages
error_messages={‘key’: ‘value’}
自定义错误提示信息,键是表单里同名的错误类型字符串,值是自定义的提示信息字符串。
其中的key包括:
required,无填写内容
invalid,非法字符
maxlength,超出长度上限max_length
最大长度min_length
最小长度
requiredrequired=True/False
该字段必填/非必填。
当为True时,<表单对象>.clean(‘‘)和<表单对象>.clean(None)返回ValidationError异常。
当为False时,<表单对象>.clean(‘‘)和<表单对象>.clean(None)返回None。
labellabel=’<显示值>’
字段渲染成HTML代码的提示词,默认在后面加冒号。
如字段name = forms.CharField(label=’Your Name’),显示为HTML的
label_suffix
label_suffix=’<字符>’
自定义字符,代替label生成显示值后面的冒号。
initialinitial=’<值>’
为表单元素定义初始值,即标签中的value=,可传入值和对象。initial不会作为数据提交,表单仍需要用户填写数据。
只能用initial传递初始值,如果在渲染表单的时候传递一个初始值字典,会触发表单的验证,此时输出的HTML页面可能包含验证错误。widget
widget=<widget类>
指定渲染Widget时使用的widget类,即前端中的type类型。
可用attr参数传入一个字典,对widget添加CSS样式,如:
name = forms.CharField(widget=forms.TextInput(attrs={‘class’: ‘special’}) )
comment = forms.CharField(widget=forms.TextInput(attrs={‘size’: ‘40’}) )
help_texthelp_text=’<文本>’
设定辅助性描述文本,相当于HTML的默认显示值。validators
validators=[ ]
传入列表,包含对字段验证的函数,自定义验证方法的时候用。localize
实现表单数据输入的本地化。
disabled
disabled=True/False
设置对字段禁用/启用编辑,禁用编辑后,即使非法篡改前端页面的属性向服务器提交,该字段值也会被忽略。
参数:
参数 | 说明 |
---|---|
Required | 输入数据是否为空,默认为True |
Widget | 设置HTML控件的样式 |
Label | 生成Label标签或显示内容 |
Initial | 设置初始值 |
help_text | 设置帮助提示信息 |
error_messages | 设置错误信息,以字典格式表示:{‘required’:‘不能为空’,‘invalid’:‘格式错误’} |
show_hidden_initial | 值为True或False,是否在当前控件后面再加一个 隐藏的且具有默认值的控件(可用于检验两次输入值是否一致) |
Validators | 自定义数据验证规则。以列表格式表示,列表元素为函数名 |
Lacalize | 值为True/False,是否支持本地化,如不同时区显示相应的时间 |
Disabled | 值为True/False,是否可以编辑 |
label_suffix | Label内容后缀,在Label后添加内容 |
对 ProductForm 的字段进行优化
#form.py
from django import forms
from .models import *
from django.core.exceptions import ValidationError
#自定义数据验证函数
def weight_validate(value):
if not str(value).isdigit():
raise ValidationError('请输入正确的重量 ')
class ProductForm(forms.Form):
#设置错误信息并设置样式
name = forms.CharField(max_length=20, label='名字',
widget=forms.widgets.TextInput(attrs={'class':'c2'}),
error_messages={'required':'名字不能为空'})
#使用自定义数据验证函数
weight = forms.CharField(max_length=50, label='重量',
validators=[weight_validate])
size = forms.CharField(max_length=50, label='尺寸')
#设置下拉框的值
## choices_list = [(1,'手机'),(2, '平板')]
choices_list = [(i+1, v['type_name']) for i,v in enumerate(Type.objects.values('type_name'))]
#设置CSS样式
type = forms.ChoiceField(widget=forms.widgets.Select(attrs={'class':'type','size':3}),
choices=choices_list, label='产品类型')
优化的代码分别使用了参数widget、label、error_messages和validators,这4个参数是实际开发中常用的参数。为了进一步验证优化后的表单是否正确运行,还要对views.py的视图函数index代码进行优化
#views.py 的 index 函数
from django.http import HttpResponse
from django.shortcuts import render
from .form import *
def index(request):
#GET请求
if request.method == 'GET':
product = ProductForm()
return render(request, 'data_form.html', locals())
#POST请求
else:
product = ProductForm(request.POST)
if product.is_valid():
#获取网页控件name的数据
#方法1
#name = product['name']
#方法2
#cleaned_data将控件name的数据进行清洗,转换成Python数据类型
name = product.cleaned_data['name']
return HttpResponse('提交成功')
else:
#将错误信息输出,error_msg是将错误信息以json格式输出
error_msg = product.errors.as_json()
return render(request, 'data_form.html', locals())
- 用户首次访问url地址时,等于向项目发送一个GET请求,函数index将表单ProductForm实例化并传递给模板,由模板引擎生成HTML表单返回给用户。
- 当用户在表单中输入相关信息并提交时,等于向项目发送一个POST请求,函数index首先获取表单数据对象product,然后由is_valid()方法对数据对象product进行数据验证。
- 如果验证成功,可以使用product[‘name’]或prodcut.cleaned_data[‘name’]方法来获取用户在某个控件上的输入值,实现表单和模型的信息交互。
下面来验证一下是否能正常工作,在姓名栏输入了空格
验证正常工作了。 - 在上述例子中,模板data_form.html的表单是使用HTML的标签展现在网页上,除此之外,表单还可以用其他HTML标签展现,只需将模板data_form.html的对象product使用以下方法即可生成其他HTML标签:
参数 | 说明 |
---|---|
{{ product.as_ul }} | 将表单生成HTML的 ul 标签 |
{{ product.as_p }} | 将表单生成HTML的 p 标签 |
{{ product.type }} | 生成单个HTML元素控件 |
{{ product.type.label }} | 获取表单字段的参数 label 属性值 |
数据表单django.forms.ModelForm
数据表单(ModelForm)
数据表单是将模型的字段转换成表单的字段,再从表单的字段生成HTML的元素控件。
Django通过ModelForm表单功能模块实现了表单数据与模型数据之间的交互开发。
首先再form.py中定义表单ProductModelForm。该类可分为三大部分:
添加模型外的表单字段、模型与表单设置和自定义表单字段的数据清洗。
from django import forms
from .models import *
from django.core.exceptions import ValidationError
#数据库表单
class ProductModelForm(forms.ModelForm):
#步骤1:添加模型外的表单字段
productId = forms.CharField(max_length=20, label='产品序号')
#步骤2:模型与表单设置
class Meta:
#绑定模型,必选
model = Product
#设置转换字段,必选,属性值为'__all__'时全部转换
#fields = '__all__'
fields = ['name','weight','size','type']
#禁止模型转换的字段,可选,若设置了该属性,fields则可以不设置
exclude = []
#设置HTML元素控件的label标签,可选
labels = {'name':'产品名称',
'weight':'重量',
'size':'尺寸',
'type':'产品类型',
}
#设置表单字段的CSS样式,可选
widgets = {'name':forms.widgets.TextInput(attrs={'class':'c1'}),
}
#定义字段的类型,可选,默认时自动转换的
field_classes = {
'name': forms.CharField,
}
#设置提示信息
help_texts = {
'name':'',
}
#自定义错误信息
error_messages = {
#设置全部错误信息
'__all__':{'required':'请输入内容',
'invalid':'请检查输入内容'},
#设置某个字段的错误信息
'weight':{'required':'请输入重量数值',
'invalid':'请检查数值是否正确'},
}
#步骤3: 自定义表单字段的数据清洗
def clean_weight(self):
#获取字段weight的值
data = self.cleaned_data['weight']
return data + 'g'
模型字段
模型字段转换成表单字段主要在类Meta中实现,由类Meta的属性实现两者之间的转换,其属性说明如下:
属性 | 说明 |
---|---|
model | 必需属性,用于绑定Model对象 |
fields | 必需属性,设置模型内哪些字段转换成表单字段。属性值为"all"时表示整个模型的字段,若设置一个或多个,使用列表或元组表示,列表或元组里的元素是模型的字段名 |
exclude | 可选属性,与fields相反,表示禁止模型哪些字段转换成表单字段。若设置了该属性,则属性fields可以不用设置 |
labels | 可选属性,设置表单字段里的参数label。属性值以字典表示,字典的键是模型的字段 |
widgets | 可选属性,设置表单字段里的参数widget |
field_classes | 可选,将模型的字段类型重新定义为表单字段类型,默认模型字段类型会自动转换为表单字段类型 |
help_texts | 可选,设置表单字段里的参数help_text |
error_messages | 可选,设置表单字段里的参数error_messages |
需要注意的是,一些较为特殊的模型字段在转换表单时会有不同的处理方式。例如模型字段的类型为AutoField,该字段在表单中不存在对应的表单字段;模型字段类型为ForeignKey和ManyToManyField,在表单中对应的表单字段为ModelChoiceField和ModelMultipleChoiceField。
在自定义数据清洗函数时,必须以“clean_字段名”的格式作为函数名,而且函数必须有return返回值。如果在函数中设置了ValidationError异常抛出,那么该函数可视为带有数据验证的清洗函数。
通过定义表单类ProductModelForm将模型Product与表单相互结合起来后,还要通过视图函数来使用和展现表单,继续沿用前面的模板data_form.html,在项目的urls.py和views.py中分别定义新的URL地址和视图函数:
#urls.py
path('<int:id>.html', views.model_index),
#views.py 的视图函数 model_index
def model_index(request, id):
if request.method == 'GET':
instance = Product.objects.filter(id=id)
#判断数据是否存在
if instance:#如果存在,将数据传递给参数instance
product = ProductModelForm(instance=instance[0])
else:#如果不存在,为name字段设置一个默认值
product = ProductModelForm(initial={'name':'iphone XS'})
return render(request, 'data_form.html',locals())
else:
product = ProductModelForm(request.POST)
if product.is_valid():
#获取并清洗weight的数据
weight = product.cleaned_data['weight']
#数据保存方法1:直接保存到数据库
## product.save()
#数据保存方法2:save方法设置commit=False,将生成数据库对象product_db,
#然后对该对象的属性值修改并保存
product_db = product.save(commit=False)
product_db.name = '我的 iphone'
product_db.save()
#数据保存方法3:save_m2m()保存ManyTOMany的数据模型
## product.save_m2m()
return HttpResponse('提交成功!weight清洗后的数据是:'+weight)
else:
#将错误信息以json格式输出
error_msg = product.errors.as_json()
print(error_msg)
return render(request, 'data_form.html', locals())
如果存在多个下拉框,而且每个下拉框的数据分别取同一个模型的不同字段,那么可以在定义表单类的时候重写初始化函数__init__()
#forms.py
class ProductModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ProductModelForm, self).__init__(*args, **kwargs)
#设置下拉框的数据
type_obj = Type.objects.values('type_name')
choices_list = [(i+1, v['type_name']) for i,v in enumerate(Type.objects.values('type_name'))]
self.fields['type'].choices = choices_list
#初始化字段name
self.fields['name'].initial = '我的手机'
表单初始化
表单初始化的方法有以下几种:
- 在视图函数中对表单实例化时,设置实例化对象的参数initial。如product = ProductModelForm(initial={‘name’:‘iphone XS’}),参数值以字典格式表示,字典键为表单的字段名,该方法适用于所有表单类。
- 在表单类中进行实例化时,如果初始化的数据是一个模型对象的数据,可设置参数instance,如product = ProductModelForm(instance=instance[0]),该方法只适用于ModelForm.
- 定义表单字段时,对表单字段设置初始化参数initial,此方法不适用于ModelForm,如name = forms.CharField(initial=‘我的手机’)。
- 重写表单类的初始化函数 init,适用于所有表单类,如在初始化函数中设置slef.fields[‘name’].initial=‘我的手机’.
数据库的保存实际上只有save()和save_m2m()方法实现。save()只适合将数据保存在非多对多关系的数据表,而save_m2m只适合将数据保存在多对多关系的数据表。