Django-Form-ModelForm
一、Form简介
Form主要用于对用户输入的input标签内容进行校验,比如校验用户是否输入,输入的长度和格式等正不正确,并且有错误就需要在页面上相应的位置显示对应的错误信息。
总结:
- 生成页面可以用的HTML标签
- 对用户提交的数据进行校验
- 保留上次输入内容
示例:使用form写简单注册界面
views.py 文件
from django.shortcuts import render, HttpResponse
from django import forms
class Register(forms.Form):
name = forms.CharField(
label='用户名:', # 设置label值
min_length=6, # 最小6个字符
)
password = forms.CharField(
label='密码:',
min_length=6, # 最小6个字符
max_length=11, # 最大11个字符
# 设置input的type属性为password
widget=forms.widgets.PasswordInput(attrs={'type': 'password'})
)
def register(request):
form_obj = Register()
if request.method == 'GET':
return render(request, 'register.html', {'form_obj': form_obj})
else:
# 实例化form对象,并把post提交过来的数据传递进去
form_obj = Register(data=request.POST)
# 调用form_obj校验数据
if form_obj.is_valid():
return HttpResponse('注册成功!!')
return render(request, 'register.html', {'form_obj': form_obj})
register.html 文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" novalidate method="post">
{% csrf_token %}
<div>
<label for="{{ form_obj.name.id_for_label }}">{{ form_obj.name.label }}</label>
{{ form_obj.name }} <!-- 会渲染成input标签 -->
<!-- 该字段的错误文本信息! -->
<span style="color:red">{{ form_obj.name.errors.0 }}</span>
</div>
<div>
<label for="{{ form_obj.password.id_for_label }}">{{ form_obj.password.label }}</label>
{{ form_obj.password }}
<span style="color: red">{{ form_obj.password.errors.0 }}</span>
</div>
<input type="submit">
</form>
</body>
</html>
二、Form常用字段
创建Form类时,主要涉及到【字段】和【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML。
initial
初始值,input框里面的初始值。
class Text(forms.Form):
name = forms.CharField(
label='用户名',
initial='默认值',
)
error_messages
重写错误信息
class Text(forms.Form):
name = forms.CharField(
label='用户名',
initial='小杨',
min_length=6,
error_messages={
'required': '不能为空',
'invalid': '格式错误',
'min_length': '用户名最短6位',
}
)
password
class Text(forms.Form):
password = forms.CharField(
min_length=6,
label='密码',
widget=forms.widgets.PasswordInput(
attrs={
'class': 'c1', # 设置该标签class=c1
'type': 'password', # 设置该标签type=password
}
)
)
RadioSelect
单选
class Text(forms.Form):
sex = forms.ChoiceField(
label='性别',
initial=1, # 默认选择男
widget=forms.widgets.RadioSelect(), # 单选
choices=(
(1, '男'), # 1——>为提交的值
(2, '女'), # ’女‘——>为页面显示的值
)
)
单选Select
单选下拉框
class Text(forms.Form):
sex = forms.ChoiceField(
label='性别',
initial=1, # 默认选择男
widget=forms.widgets.Select(), # 插件为Select单选
choices=(
(1, '男'), # 1——>为提交的值
(2, '女'), # ’女‘——>为页面显示的值
)
)
多选Select
多选下拉框
class Text(forms.Form):
hobby = forms.MultipleChoiceField( # 多选框的时候用MultipleChoiceField
label='爱好',
initial=1, # 默认选择篮球
widget=forms.widgets.SelectMultiple(), # 对选插件为SelectMultiple
choices=(
(1, '篮球'), # 1——>为提交的值
(2, '跑步'), # ’跑步‘——>为页面显示的值
(3, '运动'),
(4, '听歌'),
)
)
单选Checkbox
class Text(forms.Form):
keep = forms.ChoiceField(
label='是否7天自动登录',
initial='1', # 默认选中
choices=(
('True', 1), # 选中就为True
('False', 0), # 没选中就为False
),
widget=forms.widgets.CheckboxInput(),
)
多选Checkbox
class Text(forms.Form):
hobby = forms.MultipleChoiceField(
label='爱好',
initial=1, # 默认选中
choices=(
(1, '篮球'), # 1——>为提交的值
(2, '跑步'), # ’跑步‘——>为页面显示的值
(3, '运动'),
(4, '听歌'),
),
widget=forms.widgets.CheckboxSelectMultiple(),
)
date类型
date必须指定type
class Text(forms.Form):
date = forms.DateField(
initial='时间',
widget=forms.widgets.TextInput(
attrs={
'type': 'date', # 必须设置为date类型
}
)
)
数据库动态获取数据构造标签
由于使用标签时,需要从配置的数据库中获取,但是上面所写的都是静态,无法实时更新,可以使用以下两种方法
方法一:重写init方法。但是*args和**kwargs一定要写上
from django.shortcuts import render
from django import forms
from app01 import models
class Text(forms.Form):
city = forms.ChoiceField(
initial=1,
widget=forms.widgets.Select()
)
def __init__(self, *args, **kwargs): # 必须加*args和**kwargs
super().__init__(*args, **kwargs)
# 把数据库查询的值赋值给city字段的choice里去
self.fields['city'].choices = models.City.objects.all().values_list('id', 'name')
print(self.fields['city'].choices) # [(1, '上海'), (2, '成都'), (3, '重庆')]
方法二:
from django.shortcuts import render
from django import forms
from app01 import models
class Text(forms.Form):
city = forms.ModelMultipleChoiceField(
queryset=models.City.objects.all()
"""
注意:
如果用这种方法,需要在City类表中加上__str__方法,不然显示的是一个个object对象
"""
)
批量添加样式
通过重写Form类的init方法来实现
from django.shortcuts import render, HttpResponse
from django import forms
class Text(forms.Form):
password = forms.CharField(
label='密码',
widget=forms.widgets.PasswordInput(attrs={
'type': 'password',
})
)
re_password = forms.CharField(
label='确认密码',
widget=forms.widgets.PasswordInput(attrs={
'type': 'password',
})
)
# 获取所有的字段self.fields循环添加
def __init__(self, *args, **kwargs):
super().__init__(self, *args, **kwargs)
for field in iter(self.fields):
self.fields[field].widget.attrs.update(
{'class': 'c1'}
)
三、字段校验
对前端提交的数据进行校验并返回错误。
RegexValidator验证器
可以写多个验证,以逗号分割
from django.shortcuts import render
from django import forms
from django.core.validators import RegexValidator # 需要导入模块
class Text(forms.Form):
count = forms.CharField(
validators=[
RegexValidator(r'^\d{4}$', '错误,只能是4位数字!'),
RegexValidator(r'正则', '错误信息'),
]
)
自定义验证函数
自定义验证规则的时候,如果不符合规则,需要自己发起错误
import re
from django.shortcuts import render, HttpResponse
from django import forms
from django.core.exceptions import ValidationError
def verify(value):
value_re = re.compile(r'^\d{4}$')
if not value_re.match(value):
# 自定义验证需要自己发起错误
raise ValidationError('错误,只能是4位数字')
class Text(forms.Form):
count = forms.CharField(
label='输入值:',
validators=[verify, ], # 调用自定义验证规则,可以调用多个。
)
四、Hook钩子
在Form类中定义钩子函数,用来实现自定义的验证功能
局部钩子
在Form类中定义clean_字段名()方法,就能够实现对特定字段进行校验。
import re
from django.shortcuts import render
from django import forms
from django.core.exceptions import ValidationError
class Text(forms.Form):
count = forms.CharField(
label='值:',
initial='123',
error_messages={
'required': '不能为空'
}
)
# 局部钩子,对count字段进行验证
def clean_count(self):
value = self.cleaned_data.get('count') # 获取count字段的值
value_re = re.compile(r'^\d{4}$') # 创建正则规则
if not value_re.match(value): # 判断带入值是否符合要求
raise ValidationError('错误,只能是4位数字!')
else:
return value
全局钩子
在Form类中定义clean()方法,实现对字段进行全局校验。
示例:密码确认
class Text(forms.Form):
password = forms.CharField(
label='密码',
widget=forms.widgets.PasswordInput(attrs={
'type': 'password',
})
)
re_password = forms.CharField(
label='确认密码',
widget=forms.widgets.PasswordInput(attrs={
'type': 'password',
})
)
# 执行全局钩子的时候,cleaned_data里面肯定是有了通过前面验证的所有数据
def clean(self):
password_value = self.cleaned_data.get('password') # 获取password值
re_password_value = self.cleaned_data.get('re_password') # 获取re_password值
if password_value == re_password_value:
return self.cleaned_data # 全局钩子要返回所有的数据
else:
# 在re_password字段增加这个错误,并且情况该字段值
self.add_error('re_password', '两次密码不一致')
raise ValidationError('两次密码不一致')
五、ModelForm
Django中大部分的表单都是与Django的模型有映射关系的。
因此Django提供了一个辅助类用来从Django的模型中创建Form,就是ModelForm。
ModelForm定义
ModelForm是Form和model的结合,会根据model的字段转换成对应的form字段,并且生成标签。
ModelForm通过原类meta里面的model对应的属性的表,去找它,并把表里面的属性filed全部转换成了form对应的filed
示例:
models.py 文件
from django.db import models
class Book(models.Model):
name = models.CharField(max_length=32)
publishDate = models.DateField()
price = models.CharField(max_length=4)
views.py 文件
from django.shortcuts import render
from django import forms
from app01 import models
class ModelForm_book(forms.ModelForm):
# 定义一个元类
class Meta():
model = models.Book # 获取model对应的属性的表
fields = '__all__' # 转换所有字段
# 设置字段名labels
labels = {
'name': '书名',
'publishDate': '出版日期',
'price': '价格',
}
# 给字段加属性
widgets = {
'publishDate': forms.widgets.TextInput(attrs={'type': 'date'})
}
# 定义错误信息
error_messages = {
'name': {'required': '不能为空'}
}
def book(request):
# 获取数据
book_obj = models.Book.objects.filter(pk=1).first()
# 添加到modelform类中
# 前端就会根据对应的数据默认显示
book_model_form = ModelForm_book(instance=book_obj)
return render(request, 'book.html', locals())
book.html 文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" novalidate>
{% for book in book_model_form %}
<div>
<label for="book.id_for_label">{{ book.label }}</label>
{{ book }}
{{ book.errors.0 }}
</div>
{% endfor %}
<input type="submit">
</form>
</body>
</html>
class Meta: 常用参数
model = models.Book # 对应的Model中的类
fields = "__all__" # 字段,如果是__all__,就是表示列出所有的字段
exclude = None # 排除的字段
labels = None # 提示信息
help_texts = None # 帮助提示信息
widgets = None # 自定义插件
error_messages = None # 自定义错误信息
error_messages = {
'title':{'required':'不能为空'}
}
save() 方法
save() 方法是每个ModelForm都具有的方法, 这个方法会根据表单绑定的数据, 创建并保存到对应的数据库中, 另外ModelForm类中接收instance参数----->(记录对象), 则传入的数据则会更新该记录对象, 如果没有提供save()则会创建一条记录
添加记录
class ModelForm_book(forms.ModelForm):
# 定义一个元类
class Meta:
model = models.Book
fields = '__all__'
# 设置字段名labels
labels = {
'name': '书名',
'publishDate': '出版日期',
'price': '价格',
}
def book(request):
if request.method == 'GET':
# 获取记录对象数据
book_obj = models.Book.objects.filter(pk=1).first()
# 添加到modelform类中
# 前端就会根据对应的数据默认显示
book_model_form = ModelForm_book(instance=book_obj)
return render(request, 'book.html', locals())
else:
# 数据库中创建新记录
book_obj = ModelForm_book(request.POST) # 将post提交的数据带入ModelForm里
if book_obj.is_valid(): # 数据校验
book_obj.save() # 创建新的记录
return HttpResponse('ok')
更新记录: 传入需要更新的记录对象instance参数
def book(request):
if request.method == 'GET':
# 获取记录对象数据
book_obj = models.Book.objects.filter(pk=1).first()
# 添加到modelform类中
# 前端就会根据对应的数据默认显示
book_model_form = ModelForm_book(instance=book_obj)
return render(request, 'book.html', locals())
else:
# 数据库中更新记录
# 获取需要更新的记录
update_book = models.Book.objects.filter(pk=1).first()
# 将需要更新的记录和,更新的对象传入
book_obj = ModelForm_book(request.POST, instance=update_book)
if book_obj.is_valid(): # 数据校验
book_obj.save() # 创建更新记录
return HttpResponse('ok')
本文来自博客园,作者:Mr-Yang`,转载请注明原文链接:https://www.cnblogs.com/XiaoYang-sir/articles/14964256.html