Form介绍

在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来。

与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确。如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息.。

Django form组件就实现了上面所述的功能。

总结一下,其实form组件的主要功能如下:

  • 生成页面可用的HTML标签
  • 对用户提交的数据进行校验
  • 保留上次输入内容

普通方式手写注册功能

views.py

# 注册
def register(request):
error_msg = ""
if request.method == "POST":
username = request.POST.get("name")
pwd = request.POST.get("pwd")
# 对注册信息做校验
if len(username) < 6:
# 用户长度小于6位
error_msg = "用户名长度不能小于6位"
else:
# 将用户名和密码存到数据库
return HttpResponse("注册成功")
return render(request, "register.html", {"error_msg": error_msg})

login.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册页面</title>
</head>
<body>
<form action="/reg/" method="post">
{% csrf_token %}
<p>
用户名:
<input type="text" name="name">
</p>
<p>
密码:
<input type="password" name="pwd">
</p>
<p>
<input type="submit" value="注册">
<p style="color: red">{{ error_msg }}</p>
</p>
</form>
</body>
</html>

使用form组件实现注册功能

views.py

先定义好一个RegForm类:

from django import forms

# 按照Django form组件的要求自己写一个类
class RegForm(forms.Form):
name = forms.CharField(label="用户名")
pwd = forms.CharField(label="密码")

再写一个视图函数:

# 使用form组件实现注册方式
def register2(request):
form_obj = RegForm()
if request.method == "POST":
# 实例化form对象的时候,把post提交过来的数据直接传进去
form_obj = RegForm(request.POST)
# 调用form_obj校验数据的方法
if form_obj.is_valid():
return HttpResponse("注册成功")
return render(request, "register2.html", {"form_obj": form_obj})

login2.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册2</title>
</head>
<body>
<form action="/reg2/" method="post" novalidate autocomplete="off">
{% csrf_token %}
<div>
<label for="{{ form_obj.name.id_for_label }}">{{ form_obj.name.label }}</label>
{{ form_obj.name }} {{ form_obj.name.errors.0 }}
</div>
<div>
<label for="{{ form_obj.pwd.id_for_label }}">{{ form_obj.pwd.label }}</label>
{{ form_obj.pwd }} {{ form_obj.pwd.errors.0 }}
</div>
<div>
<input type="submit" class="btn btn-success" value="注册">
</div>
</form>
</body>
</html>

看网页效果发现 也验证了form的功能:
• 前端页面是form类的对象生成的                                      -->生成HTML标签功能
• 当用户名和密码输入为空或输错之后 页面都会提示        -->用户提交校验功能
• 当用户输错之后 再次输入 上次的内容还保留在input框   -->保留上次输入内容

Form那些事儿

常用字段与插件

创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML;

initial

初始值,input框里面的初始值。

class LoginForm(forms.Form):
username = forms.CharField(
min_length=8,
label="用户名",
initial="张三" # 设置默认值
)
pwd = forms.CharField(min_length=6, label="密码")

error_messages

重写错误信息。

class LoginForm(forms.Form):
username = forms.CharField(
min_length=8,
label="用户名",
initial="张三",
error_messages={
"required": "不能为空",
"invalid": "格式错误",
"min_length": "用户名最短8位"
}
)
pwd = forms.CharField(min_length=6, label="密码")

password

class LoginForm(forms.Form):
...
pwd = forms.CharField(
min_length=6,
label="密码",
widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True)
)

radioSelect

单radio值为字符串

class LoginForm(forms.Form):
username = forms.CharField(
min_length=8,
label="用户名",
initial="张三",
error_messages={
"required": "不能为空",
"invalid": "格式错误",
"min_length": "用户名最短8位"
}
)
pwd = forms.CharField(min_length=6, label="密码")
gender = forms.fields.ChoiceField(
choices=((1, "男"), (2, "女"), (3, "保密")),
label="性别",
initial=3,
widget=forms.widgets.RadioSelect()
)

单选Select

class LoginForm(forms.Form):
...
hobby = forms.fields.ChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
label="爱好",
initial=3,
widget=forms.widgets.Select()
)

多选Select

class LoginForm(forms.Form):
...
hobby = forms.fields.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
label="爱好",
initial=[1, 3],
widget=forms.widgets.SelectMultiple()
)

单选checkbox

class LoginForm(forms.Form):
...
keep = forms.fields.ChoiceField(
label="是否记住密码",
initial="checked",
widget=forms.widgets.CheckboxInput()
)

多选checkbox

class LoginForm(forms.Form):
...
hobby = forms.fields.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.CheckboxSelectMultiple()
)

choice字段注意事项

在使用选择标签时,需要注意choices的选项可以配置从数据库中获取,但是由于是静态字段 获取的值无法实时更新,需要重写构造方法从而实现choice实时更新。

方式一:

from django.forms import Form
from django.forms import widgets
from django.forms import fields class 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'].choices = ((1, '上海'), (2, '北京'),)
# 或
self.fields['user'].choices = models.Classes.objects.all().values_list('id','caption')

方式二:

from django import forms
from django.forms import fields
from django.forms import models as form_model class FInfo(forms.Form):
authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all()) # 多选
# authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all()) # 单选

Django Form所有内置字段

Field
required=True, 是否允许为空
widget=None, HTML插件
label=None, 用于生成Label标签或显示内容
initial=None, 初始值
help_text='', 帮助信息(在标签旁边显示)
error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'}
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 Form内置字段

字段校验

RegexValidator验证器

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator class MyForm(Form):
user = fields.CharField(
validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
)

自定义验证函数

import re
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.exceptions import ValidationError # 自定义验证规则
def mobile_validate(value):
mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
if not mobile_re.match(value):
raise ValidationError('手机号码格式错误') class PublishForm(Form): title = fields.CharField(max_length=20,
min_length=5,
error_messages={'required': '标题不能为空',
'min_length': '标题最少为5个字符',
'max_length': '标题最多为20个字符'},
widget=widgets.TextInput(attrs={'class': "form-control",
'placeholder': '标题5-20个字符'})) # 使用自定义验证规则
phone = fields.CharField(validators=[mobile_validate, ],
error_messages={'required': '手机不能为空'},
widget=widgets.TextInput(attrs={'class': "form-control",
'placeholder': u'手机号码'})) email = fields.EmailField(required=False,
error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))

Hook方法

除了上面两种方式,我们还可以在Form类中定义钩子函数,来实现自定义的验证功能。

局部钩子

我们在Fom类中定义 clean_字段名() 方法,就能够实现对特定字段进行校验。

举个例子:

class LoginForm(forms.Form):
username = forms.CharField(
min_length=8,
label="用户名",
initial="张三",
error_messages={
"required": "不能为空",
"invalid": "格式错误",
"min_length": "用户名最短8位"
},
widget=forms.widgets.TextInput(attrs={"class": "form-control"})
)
...
# 定义局部钩子,用来校验username字段
def clean_username(self):
value = self.cleaned_data.get("username")
if "" in value:
raise ValidationError("光喊666是不行的")
else:
return value

全局钩子

我们在Fom类中定义 clean() 方法,就能够实现对字段进行全局校验。

class LoginForm(forms.Form):
...
password = forms.CharField(
min_length=6,
label="密码",
widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}, render_value=True)
)
re_password = forms.CharField(
min_length=6,
label="确认密码",
widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}, render_value=True)
)
...
# 定义全局的钩子,用来校验密码和确认密码字段是否相同
def clean(self):
password_value = self.cleaned_data.get('password')
re_password_value = self.cleaned_data.get('re_password')
if password_value == re_password_value:
return self.cleaned_data
else:
self.add_error('re_password', '两次密码不一致')
raise ValidationError('两次密码不一致')

补充进阶

应用Bootstrap样式

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
<title>login</title>
</head>
<body>
<div class="container">
<div class="row">
<form action="/login2/" method="post" novalidate class="form-horizontal">
{% csrf_token %}
<div class="form-group">
<label for="{{ form_obj.username.id_for_label }}"
class="col-md-2 control-label">{{ form_obj.username.label }}</label>
<div class="col-md-10">
{{ form_obj.username }}
<span class="help-block">{{ form_obj.username.errors.0 }}</span>
</div>
</div>
<div class="form-group">
<label for="{{ form_obj.pwd.id_for_label }}" class="col-md-2 control-label">{{ form_obj.pwd.label }}</label>
<div class="col-md-10">
{{ form_obj.pwd }}
<span class="help-block">{{ form_obj.pwd.errors.0 }}</span>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{{ form_obj.gender.label }}</label>
<div class="col-md-10">
<div class="radio">
{% for radio in form_obj.gender %}
<label for="{{ radio.id_for_label }}">
{{ radio.tag }}{{ radio.choice_label }}
</label>
{% endfor %}
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-default">注册</button>
</div>
</div>
</form>
</div>
</div> <script src="/static/jquery-3.2.1.min.js"></script>
<script src="/static/bootstrap/js/bootstrap.min.js"></script>
</body>
</html>

Django form应用Bootstrap样式简单示例

批量添加样式

可通过重写form类的init方法来实现。

class LoginForm(forms.Form):
username = forms.CharField(
min_length=8,
label="用户名",
initial="张三",
error_messages={
"required": "不能为空",
"invalid": "格式错误",
"min_length": "用户名最短8位"
}
... def __init__(self, *args, **kwargs):
super(LoginForm, self).__init__(*args, **kwargs)
for field in iter(self.fields):
self.fields[field].widget.attrs.update({
'class': 'form-control'
})

批量添加样式

ModelForm

通常在Django项目中,我们编写的大部分都是与Django 的模型紧密映射的表单。 举个例子,你也许会有个Book 模型,并且你还想创建一个form表单用来添加和编辑书籍信息到这个模型中。 在这种情况下,在form表单中定义字段将是冗余的,因为我们已经在模型中定义了那些字段。

基于这个原因,Django 提供一个辅助类来让我们可以从Django 的模型创建Form,这就是ModelForm。

modelForm定义

form与model的终极结合。

class BookForm(forms.ModelForm):

    class Meta:
model = models.Book
fields = "__all__"
labels = {
"title": "书名",
"price": "价格"
}
widgets = {
"password": forms.widgets.PasswordInput(attrs={"class": "c1"}),
}
class StudentList(ModelForm):
class Meta:
model = models.UserInfo #对应的Model中的类
fields = "__all__" #字段,如果是__all__,就是表示列出所有的字段
exclude = None #排除的字段
labels = None #提示信息
help_texts = None #帮助提示信息
widgets = None #自定义插件
error_messages = None #自定义错误信息
#error_messages用法:
error_messages = {
'name':{'required':"用户名不能为空",},
'age':{'required':"年龄不能为空",},
} #widgets用法,比如把输入用户名的input框给为Textarea
#首先得导入模块
from django.forms import widgets as wid #因为重名,所以起个别名
widgets = {
"name":wid.Textarea(attrs={"class":"c1"}) #还可以自定义属性
}
#labels,自定义在前端显示的名字
labels= {
"name":"用户名"

参数用法

class Meta下常用参数:

model = models.Book  # 对应的Model中的类
fields = "__all__" # 字段,如果是__all__,就是表示列出所有的字段
exclude = None # 排除的字段
labels = None # 提示信息
help_texts = None # 帮助提示信息
widgets = None # 自定义插件
error_messages = None # 自定义错误信息

ModelForm的验证

与普通的Form表单验证类型类似,ModelForm表单的验证在调用is_valid() 或访问errors 属性时隐式调用。

我们可以像使用Form类一样自定义局部钩子方法和全局钩子方法来实现自定义的校验规则。

如果我们不重写具体字段并设置validators属性的化,ModelForm是按照模型中字段的validators来校验的。

save()方法

每个ModelForm还具有一个save()方法。 这个方法根据表单绑定的数据创建并保存数据库对象。 ModelForm的子类可以接受现有的模型实例作为关键字参数instance;如果提供此功能,则save()将更新该实例。 如果没有提供,save() 将创建模型的一个新实例:

>>> from myapp.models import Book
>>> from myapp.forms import BookForm # 根据POST数据创建一个新的form对象
>>> form_obj = BookForm(request.POST) # 创建书籍对象
>>> new_ book = form_obj.save() # 基于一个书籍对象创建form对象
>>> edit_obj = Book.objects.get(id=1)
# 使用POST提交的数据更新书籍对象
>>> form_obj = BookForm(request.POST, instance=edit_obj)
>>> form_obj.save()

Django Form and ModelForm的更多相关文章

  1. Django Form and Modelform Admin定义 高级查询)

    Django的form表单一般具有两种功能 1. 验证输入 2.输入HTML ---------模板----------- from django import forms class BookFor ...

  2. Django Form和ModelForm组件

    Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否 ...

  3. Django - Form和ModelForm

    [TOC] 一. form介绍 1.生成页面可用的HTML标签 2. 提供input可以提交数据 3. 对用户提交的数据进行校验 4. 保留上次输入内容 5. 提供错误信息 二. 普通方式书写注册功能 ...

  4. Django—Form、ModelForm

    一.Form form.py from django import forms from django.core.exceptions import ValidationError from djan ...

  5. django form 和modelform样式设置

      目录 1.form通过attr设置属性 2.输入框设置表单状态 3.modelform的使用 4.结合modelform 使用for循环生成输入框 5.基于init构造方法设置样式 6.基本增删改 ...

  6. Django之 Form和ModelForm组件

    01-Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用 ...

  7. Django之Form、ModelForm 组件

    Django之Form.ModelForm 组件 一.Form组件: django框架提供了一个form类,来处理web开发中的表单相关事项.众所周知,form最常做的是对用户输入的内容进行验证,为此 ...

  8. {Django基础十之Form和ModelForm组件}一 Form介绍 二 Form常用字段和插件 三 From所有内置字段 四 字段校验 五 Hook钩子方法 六 进阶补充 七 ModelForm

    Django基础十之Form和ModelForm组件 本节目录 一 Form介绍 二 Form常用字段和插件 三 From所有内置字段 四 字段校验 五 Hook钩子方法 六 进阶补充 七 Model ...

  9. Django Form&ModelForm

    ModelForm: 首先导入所需模块 from django.forms import ModelFormfrom django.forms import widgets as form_widge ...

随机推荐

  1. InfluxDB常见疑问与解答 - 数据写入时如何在表级别指定保留策略

    网友Siguoei:我想让一个库中不同的measurment能够指定不同的保存策略.而不是写入时使用数据库的默认保留策略. Answer:这个特性InfluxDB支持的,写入时序数据时,在行协议前加上 ...

  2. ssh WARNING:REMOTE HOST IDENTIFICATION HAS CHANGED(警告:远程主机标识已更改)

    ssh 192.168.1.88 出现以下警告: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ WARNING: REMOT ...

  3. 【JAVA】可视化计算器

    import java.awt.Color; import java.awt.Font; import java.awt.GridLayout; import java.awt.event.Actio ...

  4. 运用wxs制作微信小程序左滑功能和跳转,性能更优越

    锲子 微信小程序自定义左滑功能加上跳转,换成以往,左滑功能的逻辑一般是在js中实现,但在拖动方面,性能并不是那么的流畅.如今,官方新扩展了一套脚本语言wxs,在IOS设备上运行,性能会比JS快2~20 ...

  5. 中小学生试卷自动生成程序--jialin大佬代码分析

    结对编程代码评价 有幸和小jialin结对编程.拿到jialin的代码后. 我先是尝试用idea运行.结果报了如下错误. 无法加载主类,再尝试用eclipse运行. 好的,可以运行,那为什么用idea ...

  6. 浅谈Spring AOP 面向切面编程 最通俗易懂的画图理解AOP、AOP通知执行顺序~

    简介 我们都知道,Spring 框架作为后端主流框架之一,最有特点的三部分就是IOC控制反转.依赖注入.以及AOP切面.当然AOP作为一个Spring 的重要组成模块,当然IOC是不依赖于Spring ...

  7. CSPS 模拟 70

    考试结束看A了两题就有点遗憾开开心心地去颓废了 吐槽一下这局LRS开的有点睿智,SD当的有点累 T1跟前边一个T1挺像,打表也可以 T2智障dp,开滚动数组就不会被卡空间了 T3牛逼构造题,虽然不是很 ...

  8. SpringBoot Web篇笔记(一)

    摘要 文章是根据江南一点雨(松哥)的视频进行总结 江南一点雨博客 全局异常处理 通常情况下,我们都需要对自己定义的异常进行相应的处理.捕获指定的异常方式如下: @ControllerAdvice pu ...

  9. Ansible之系列命令详解

    ansible系列命令有:ansible.ansible-doc.ansible-playbook.ansible-vault.ansible-console.ansible-galaxy.ansib ...

  10. ES6学习笔记01 -- 暂时性死区 ( temporal dead zone )

    参考文档: let 和 const 命令 - ECMAScript6入门  暂时性死区(temporal dead zone) 理解ES6中的TDZ(暂时性死区) ES6 中 let 暂时性死区详解 ...