Django的Forms组件主要有以下几大功能:

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

一、小试牛刀

  1、定义Form类

from django import forms

class EmpForm(forms.Form):
name = forms.CharField(min_length=5, label="姓名", error_messages={"required": "该字段不能为空!",
"min_length": "用户名太短。"})
age = forms.IntegerField(label="年龄")
salary = forms.DecimalField(max_digits=5, decimal_places=2, label="工资")
class Emp(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
salary = models.DecimalField(max_digits=8, decimal_places=2)

Form类的字段与app01/models.py要相对应

  2、设计url与视图对应关系

from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
path('add_emp/', views.add_emp),
]

  3、视图函数

from django.shortcuts import render,redirect
from app01 import models # Create your views here.
from django.http.response import HttpResponse
def index(request): return HttpResponse("okok!") from app01.MyForms import EmpForm def add_emp(request):
if request.method == "GET":
form = EmpForm() # 初始化form对象
return render(request, "add_emp.html", {"form":form}) #传送一个实例对象
else:
form = EmpForm(request.POST) # 将数据传给form对象
if form.is_valid(): # 进行校验
data = form.cleaned_data # 校验通过的数据,字典
print(data)#{'name': 'alex01', 'age': 12, 'salary': Decimal('21')}
models.Emp.objects.create(**data)
return redirect("/index/")
else: # 校验失败
print(form.errors) #<ul class="errorlist"><li>name<ul class="errorlist"><li>用户名太短。</li></ul></li><li>age<ul class="errorlist"><li>This field is required.</li></ul></li><li>salary<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
'''<ul class="errorlist">
<li>
name
<ul class="errorlist">
<li>用户名太短。</li> 可能会有多个错误
...
</ul>
</li>
<li>age<ul class="errorlist"><li>This field is required.</li></ul></li>
<li>salary<ul class="errorlist"><li>This field is required.</li></ul></li>
</ul>'''
return render(request, "add_emp.html", {"form": form}) #传送一个带错误信息实例对象

  4、模板文件

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body> <h3>添加员工</h3> {#1、自己手动写HTML页面#}
{#<form action="" method="post">#}
{# <p>姓名:<input type="text" name="name"></p>#}
{# <p>年龄:<input type="text" name="age"></p>#}
{# <p>工资:<input type="text" name="salary"></p>#}
{# <input type="submit">#}
{#</form>#} {#2、通过form对象的as_p方法实现#}
{#<form action="" method="post" novalidate>#}
{# {% csrf_token %}#}
{# {{ form.as_p }}#}
{# <input type="submit">#}
{#</form>#} </body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body> <form action="" method="post" novalidate> <!--novalidate novalidate 属性规定当提交表单时不对其进行验证。如果使用该属性,则表单(浏览器)不会验证表单的输入。-->
{% csrf_token %}
<div>
<label for="id_{{ form.name.name }}">姓名</label> <!--form.name.name等价于表单类的字段名 等价于 name age salary ... -->
{{ form.name }} <span>{{ form.name.errors.0 }}<!--form.name.errors.0 表单类可能定义了多个错误信息 先显示第一个 解决完 --></span>
</div>
<div>
<label for="id_{{ form.age.name }}">年龄</label>
{{ form.age }} <span>{{ form.age.errors.0 }}</span>
</div>
<div>
<label for="id_salary">工资</label>
{{ form.salary }} <span>{{ form.salary.errors.0 }}</span>
</div> <input type="submit">
</form>
<!--以下为浏览器显示的页面-->
<!--<form action="" method="post" novalidate>-->
<!--<input type="hidden" name="csrfmiddlewaretoken" value="oVa3cSt17v5ie9bQBWo3MEBiv32zysmCAvY2QMCGHk3aDyaMFPhnR8ikIniQoA0H">-->
<!--<div>-->
<!--<label for="id_name">姓名</label>-->
<!--<input type="text" name="name" value="alex" minlength="5" required id="id_name"> <span>用户名太短。</span>-->
<!--</div>-->
<!--<div>-->
<!--<label for="id_age">年龄</label>-->
<!--<input type="number" name="age" required id="id_age"> <span>This field is required.</span>-->
<!--</div>-->
<!--<div>-->
<!--<label for="id_salary">工资</label>-->
<!--<input type="number" name="salary" step="0.01" required id="id_salary"> <span>This field is required.</span>-->
<!--</div>--> <!--<input type="submit">-->
<!--</form>--> </body>
</html>

3、自己写form对象标签

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body> <form action="" method="post" novalidate>
{% csrf_token %}
{% for field in form %} <!-- 遍历form表单类所有的字段信息 field 相当于 第三种方式的 form.name/form.age/form.salary-->
<div>
<label for="id_{{ field.name }}">{{ field.label }}</label>
<!--发现:name = forms.CharField(min_length=5, label="姓名", error_messages={"required": "该字段不能为空!","min_length": "用户名太短。"}) 表单类定义的字段属性 字段都可以在前端调用 field.label -->
{{ field }} <span>{{ field.errors.0 }}</span>
<!-- field.errors.0 跟这个error_messages={"required": "该字段不能为空!","min_length": "用户名太短。"} 有关联-->
</div>
{% endfor %}
<input type="submit">
</form> </body>
</html>

4、for循环获取标签

  附: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) 格式:--
TimeField(BaseTemporalField) 格式::
DateTimeField(BaseTemporalField)格式:-- : 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 = ((,'上海'),(,'北京'),)
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=), 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..1时候,可解析为192.0.2., PS:protocol必须为both才能启用 SlugField(CharField) 数字,字母,下划线,减号(连字符)
... UUIDField(CharField) uuid类型
...

Django内置字段

二、局部钩子和全局钩子

  1、定义Form类

from django import forms
from django.core.exceptions import ValidationError #导包 from django.core.exceptions import ValidationError
from app01 import models class EmpForm(forms.Form):
name = forms.CharField(min_length=5, label="姓名", error_messages={"required": "该字段不能为空!",
"min_length": "用户名太短。"})
age = forms.IntegerField(label="年龄")
salary = forms.DecimalField(max_digits=5, decimal_places=2, label="工资")
r_salary = forms.DecimalField(max_digits=5, decimal_places=2, label="请确认工资")
# 局部钩子
def clean_name(self): # 名称不能随便起,必须要clean_类属性名称
val = self.cleaned_data.get("name") if val.isdigit():
raise ValidationError("用户名不能全是数字。")
elif models.Emp.objects.filter(name=val):
raise ValidationError("用户名已存在。")
else:
return val def clean(self):
salary = self.cleaned_data.get("salary")
r_salary = self.cleaned_data.get("r_salary")
if salary != r_salary:
raise ValidationError("工资输入有误。")
else:
return self.cleaned_data

app01/MyForms.py自己分析的版本含源码分析

from django import forms
from django.core.exceptions import ValidationError
from app01 import models class EmpForm(forms.Form):
name = forms.CharField(min_length=5, label="姓名", error_messages={"required": "该字段不能为空!",
"min_length": "用户名太短。"})
age = forms.IntegerField(label="年龄")
salary = forms.DecimalField(max_digits=5, decimal_places=2, label="工资")
r_salary = forms.DecimalField(max_digits=5, decimal_places=2, label="请再输入工资") def clean_name(self): # 局部钩子
val = self.cleaned_data.get("name") if val.isdigit():
raise ValidationError("用户名不能是纯数字")
elif models.Emp.objects.filter(name=val):
raise ValidationError("用户名已存在!")
else:
return val def clean(self): # 全局钩子 确认两次输入的工资是否一致。
val = self.cleaned_data.get("salary")
r_val = self.cleaned_data.get("r_salary") if val == r_val:
return self.cleaned_data
else:
raise ValidationError("请确认工资是否一致。")

  2、视图函数

from django.shortcuts import render,redirect
from app01 import models # Create your views here.
from django.http.response import HttpResponse
def index(request):
return HttpResponse("okok!") from app01.MyForms import EmpForm def add_emp(request):
if request.method == "POST":
# data = request.POST.get()
form = EmpForm(request.POST)
if form.is_valid():
print(1111,form.cleaned_data)
models.Emp.objects.create(**form.cleaned_data)
else:
print(form.errors)#<ul class="errorlist"><li>name<ul class="errorlist"><li>用户名太短。</li></ul></li><li>__all__<ul class="errorlist nonfield"><li>工资输入有误。</li></ul></li></ul>
clear_errors = form.errors.get("__all__") # 获取全局钩子错误信息
return render(request, "add_emp.html", {"form": form, "clear_errors": clear_errors})
else:
form = EmpForm()
return render(request, "add_emp.html", {"form": form}) '''源码解析 MyForms.py:from django import forms 《--- views.py:from app01.MyForms import EmpForm
第一步:form = EmpForm() 生成一个EmpForm表单类对象(该类继承了from django import forms里面的forms.Form类)
第二步:POST请求接受客户的请求数据 进行验证 form = EmpForm(request.POST)---》form.is_valid()
1、
def is_valid(self):
"""Return True if the form has no errors, or False otherwise."""
return self.is_bound and not self.errors 2、 @property
def errors(self):
"""Return an ErrorDict for the data provided for the form."""
if self._errors is None:
self.full_clean()
return self._errors
3、
def full_clean(self):
"""
Clean all of self.data and populate self._errors and self.cleaned_data.
"""
self._errors = ErrorDict()
if not self.is_bound: # Stop further processing.
return
self.cleaned_data = {}
# If the form is permitted to be empty, and none of the form data has
# changed from the initial data, short circuit any validation.
if self.empty_permitted and not self.has_changed():
return self._clean_fields()
self._clean_form()
self._post_clean() 4、MyForms.py有自定义的局部钩子 就会调用 MyForms.py的局部钩子
def _clean_fields(self):
for name, field in self.fields.items():
# value_from_datadict() gets the data from the data dictionaries.
# Each widget type knows how to retrieve its own data, because some
# widgets split data over several HTML fields.
if field.disabled:
value = self.get_initial_for_field(field, name)
else:
value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
try:
if isinstance(field, FileField):
initial = self.get_initial_for_field(field, name)
value = field.clean(value, initial)
else:
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)
5、MyForms.py有自定义的全局钩子 就会调用 MyForms.py的全局钩子
def _clean_form(self):
try:
cleaned_data = self.clean()
except ValidationError as e:
self.add_error(None, e)
else:
if cleaned_data is not None:
self.cleaned_data = cleaned_data '''

app01/views.py自己分析的版本含源码分析

def add_emp(request):
if request.method == "GET":
form = EmpForm() # 初始化form对象
return render(request, "add_emp.html", {"form":form})
else:
form = EmpForm(request.POST) # 将数据传给form对象
if form.is_valid(): # 进行校验
data = form.cleaned_data
data.pop("r_salary")
models.Emp.objects.create(**data)
return redirect("/index/")
else: # 校验失败
clear_errors = form.errors.get("__all__") # 获取全局钩子错误信息
return render(request, "add_emp.html", {"form": form, "clear_errors": clear_errors})

  3、模板文件

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body> <form action="" method="post" novalidate>
{% csrf_token %}
<div>
<label for="id_{{ form.name.name }}">姓名</label>
{{ form.name }} <span>{{ form.name.errors.0 }}</span>
</div>
<div>
<label for="id_{{ form.age.name }}">年龄</label>
{{ form.age }} <span>{{ form.age.errors.0 }}</span>
</div>
<div>
<label for="id_salary">工资</label>
{{ form.salary }} <span>{{ form.salary.errors.0 }}{{ clear_errors.0 }}</span>
</div>
<div>
<label for="id_r_salary">请再输入工资</label>
{{ form.r_salary }} <span>{{ form.r_salary.errors.0 }}{{ clear_errors.0 }}</span>
</div>
<input type="submit">
</form> </body>
</html>

add_emp.html

另一种方法导入app01/models模型类的数据,其它方法与上面一致

08 Django组件-Forms组件的更多相关文章

  1. Django组件-Forms组件

    Django的Forms组件主要有以下几大功能: 页面初始化,生成HTML标签 校验用户数据(显示错误信息) HTML Form提交保留上次提交数据 一.小试牛刀 1.定义Form类 from dja ...

  2. django之forms组件

    在django中forms组件有其强大的功能,里面集合和众多的函数和方法:下面来看一下它的源码 """ Form classes """ f ...

  3. python 全栈开发,Day78(Django组件-forms组件)

    一.Django组件-forms组件 forms组件 django中的Form组件有以下几个功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显 ...

  4. django第13天(auth组件,forms组件,中间件,csrf)

    django第13天(auth组件,forms组件) auth组件 -auth组件 -auth是什么? -django内置的用户认证系统,可以快速的实现,登录,注销,修改密码.... -怎么用? -( ...

  5. Django之forms组件使用

    注册功能 1.渲染前端标签获取用户输入 >>> 渲染标签 2.获取用户输入传递到后端校验 >>> 校验数据 3.校验未通过展示错误信息 >>> 展 ...

  6. Django组件--forms组件(注册用)

    一.forms组件--校验类的使用 二.form组件--校验类的参数 三.forms组件校验的局部钩子--自定义校验规则(要看源码理解) 四.forms组件校验的全局钩子--校验form表单两次密码输 ...

  7. web框架开发-Django的Forms组件

    校验字段功能 针对一个实例:用户注册. 模型:models.py class UserInfo(models.Model): name=models.CharField(max_length=32) ...

  8. Django组件—forms组件

    forms组件: 校验字段功能: 针对一个实例:注册用户. 模型:models.py class UserInfo(models.Model): name=models.CharField(max_l ...

  9. Django组件——forms组件

    一.校验字段功能 通过注册用户这个实例来学习校验字段功能. 1.模型:models.py from django.db import models # Create your models here. ...

随机推荐

  1. sencha touch 2制作滑动DataView(无缝list)

    Ext.define('App.view.Sections', { extend: 'Ext.dataview.DataView', xtype: 'sectionslist', id: 'mainl ...

  2. Flume安装部署

    Flume安装部署 Flume的安装(非常简单) 上传安装包到数据源所在节点上,实际上不是数据源节点也是可以的,只要运行Flume的这台机器与数据源节点的这台机器能够通过某种协议进行通信即可. 然后解 ...

  3. gh-ost 号称是不需要触发器(Triggerless)支持的在线更改表结构的工具

    https://segmentfault.com/a/1190000006158503?utm_source=tuicool&utm_medium=referral

  4. [vagrant]第一次安装添加box出现问题汇总

    1.本地文件要加全文件名和协议file:/// 2.The box failed to unpackage properly. Please verify that the box file you' ...

  5. AngularJS:日期转换字符

    JS有很多类库提供日期转换函数,AngularJS也不例外.可以通过$filter来完成转换,方法如下: $filter('date')(sourceDate, "yyyy/MM/dd&qu ...

  6. CSS3 网格布局(grid layout)基础知识 - 隐式网格自己主动布局(grid-auto-rows/grid-auto-columns/grid-auto-flow)

    网格模板(grid-template)属性及其普通写法(longhands)定义了一个固定数量的轨道.构成显式网格. 当网格项目定位在这些界限之外.网格容器通过添加隐式网格线生成隐式网格轨道. 这些隐 ...

  7. javascript 使用方式

    第一种:内嵌在html节点中 <html> <body> <input type="button" onclick="document.bo ...

  8. Flume 读取JMS 消息队列消息,并将消息写入HDFS

    利用Apache Flume 读取JMS 消息队列消息.并将消息写入HDFS,flume agent配置例如以下: flume-agent.conf #name the  components on ...

  9. Java 二进制和十进制互转,二进制和BitSet互转

    /** * 二进制转十进制 * * @param binaryNumber * @return */ public static int binaryToDecimal(int binaryNumbe ...

  10. 2498 IncDec Sequence

    2498 IncDec Sequence  时间限制: 1 s  空间限制: 64000 KB  题目等级 : 钻石 Diamond 题解  查看运行结果     题目描述 Description 给 ...