forms组件、forms主键校验补充、forms组件参数补充、modelform组件
-
forms组件前戏
-
forms组件数据校验
-
forms组件渲染标签
-
forms组件展示信息
-
forms组件校验补充
-
forms组件参数补充
-
forms组件源码剖析
-
modelform组件
-
django中间件
forms组件
# 前戏
编写一个校验用户名和密码是否合法的功能
前端需要自己编写获取用户数据的各种标签
前端需要自己想方设法的展示错误的提示信息
后端需要自己想方设法的编写校验代码(很多if判断)
def ab_from_func(request):
errors_dict = {'username': '', 'password': ''}
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if username == 'jason':
errors_dict['username'] = '用户名不能为jason'
if password == '123':
errors_dict['password'] = '密码不能为123'
return render(request, 'fromPage.html',locals())
'''html'''
<form action="" method="post">
<p>username:
<input type="text" name="username">
<span style="color: red">{{ errors_dict.username }}</span>
</p>
<p>password:
<input type="text" name="password">
<span style="color: red">{{ errors_dict.password }}</span>
</p>
<input type="submit">
</form>
# forms组件
上面的三件事有一个组件可以一次性帮你搞定>>>:forms组件
1.数据校验
2.标签渲染
3.展示信息
# 基本使用
from django import forms
class MyForm(forms.Form):
# 用户名至少三个字符最多八个字符
username = forms.CharField(min_length=3,max_length=8)
# 年龄最小不能小于0 最大不能超过150
age = forms.IntegerField(min_value=0,max_value=150)
# 邮箱必须符合邮箱格式(@关键符号)
email = forms.EmailField()
forms组件数据校验
from app01 import views
# 1.判断数据是否全部符合要求
form_obj = views.MyForm({'username':'jason','age':18,'email':'123'})
form_obj.is_valid()
False # 只要有一个不符合结果都是False
# 2.获取符合校验条件的数据
form_obj.cleaned_data
{'username': 'jason', 'age': 18}
# 3.获取不符合校验规则的数据及原因
form_obj.errors
{'email': ['Enter a valid email address.']}
"""
1.form类中所有的字段数据默认都是必填的 不能少
如果想忽略某些字段 可以添加 required=False
2.form类中额外传入的字段数据不会做任何的校验 直接忽略
"""
forms组件渲染标签
"""
forms组件只负责渲染获取用户数据的标签
form表单标签和提交按钮需要自己写
渲染标签中文提示 可以使用参数 label指定 不指定默认使用字段名首字母大写
"""
方式1:
# 封装程度高 扩展性差 主要用于快速生成页面本地测试功能
<p>forms组件渲染标签的方式1</p>
{{ form_obj.as_p }}
{{ form_obj.as_ul }}
{{ form_obj.as_table }}
方式2:
# 封装程度低 扩展性较好 编写麻烦
<p>forms组件渲染标签的方式2</p>
{{ form_obj.username.label }} # 文本提示
{{ form_obj.username }} # 获取用户输入
{{ form_obj.age.label }}
{{ form_obj.age }}
{{ form_obj.email.label }}
{{ form_obj.email }}
方式3:
# 封装程度较高 扩展性高 编写简单 推荐使用
<p>forms组件渲染标签的方式3</p>
{% for form in form_obj %}
<p>
{{ form.label }}
{{ form }}
</p>
{% endfor %}
forms组件展示信息
"""
forms类中填写的校验性参数前端浏览器会识别并添加校验操作
form表单可以取消浏览器自动添加校验功能的操作
<form action="" novalidate>
"""
后端不同请求返回的forms对象一定要是相同的变量名
def ab_forms_func(request):
# 1.产生一个空对象
form_obj = MyForm()
if request.method == 'POST':
form_obj = MyForm(request.POST) # request.POST可以看成是一个字典 直接传给forms类校验 字典中无论有多少键值对都没关系 之在乎类中编写的
if form_obj.is_valid(): # 校验数据是否合法
print(form_obj.cleaned_data)
else:
print(form_obj.errors)
# 2.将该对象传递给html文件
return render(request, 'formsPage.html', locals())
'''html'''
<form action="" method="post" novalidate>
{% for form in form_obj %}
<p>
{{ form.label }} # 文本提示
{{ form }} # 获取用户数据的标签
<span style="color:red;">{{ form.errors.0 }}</span> # 展示错误信息
</p>
{% endfor %}
<input type="submit">
</form>
'''针对错误信息的提示可以修改成各国语言'''
方式1:自定义内容
给字段对象添加errors_messages参数
username = forms.CharField(min_length=3, max_length=8, label='用户名',
error_messages={
'min_length': '用户名最少三个字符',
'max_length': '用户名最多八个字符',
'required': '用户名不能为空'
}
)
方式2:修改系统语言环境
from django.conf import global_settings django内部真正的配置文件
forms组件之钩子函数
'''
forms组件针对字段数据的校验 提供了三种类型的校验方式(可以一起使用)
第一种类型:直接填写参数 max_length
第二种类型:使用正则表达式 validators
第三种类型:钩子函数 编写代码自定义校验规则
'''
class MyForm(forms.Form):
username = forms.CharField(min_length=3, max_length=8, label='姓名')
password = forms.CharField(min_length=3, max_length=8, label='密码')
confirm_pwd = forms.CharField(min_length=3, max_length=8, label='确认密码')
钩子函数>>>:校验的最后一环 是在字段所有的校验参数之后触发
局部钩子:每次只校验一个字段数据 校验用户名是否已存在
def clean_username(self): # 自动生成的函数名 专门用于对name字段添加额外的校验规则
# 先获取用户名
username = self.cleaned_data.get('username')
if username == 'jason':
self.add_error('username', '用户名jason已存在')
# add_error内 第一个放 要设置的字段 第二个放 展示的错误信息
return username
# 最后将勾上来的username返回出去
# 全局钩子:一次可以校验多个字段数据 校验两次密码是否一致
def clean(self):
password = self.cleaned_data.get('password')
confirm_pwd = self.cleaned_data.get('confirm_pwd')
# 判断两次密码是否一致
if not password == confirm_pwd:
self.add_error('confirm_pwd', '两次密码不一致')
# add_error内 第一个放 要设置的字段 第二个放 展示的错误信息
return self.cleaned_data
forms组件参数补充
min_length 最小字符
max_length 最大字符
min_value 最小值
max_value 最大值
label 字段注释
error_messages 错误提示
validators 正则校验器
validators=[
RegexValidator(r'^[0-9]+$', '手机号必须为数字'),
RegexValidator(r'^188[0-9]+$', '数字必须以188开头')
]
initial 默认值
required 是否必填
widget 控制标签的各项属性
widget=forms.widgets.PasswordInput(attrs={'class': 'form-control', 'username': 'jason'})
from django.forms import widgets
password = forms.IntegerField(label='密码', widget=forms.PasswordInput(attrs={'class': 'form_control'}))
forms组件字段类型
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) 格式:2015-09-01
TimeField(BaseTemporalField) 格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
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 = ((0,'上海'),(1,'北京'),)
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=20), 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.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
SlugField(CharField) 数字,字母,下划线,减号(连字符)
...
UUIDField(CharField) uuid类型
forms组件源码剖析
"""
看源码可以提升编程能力(CBV源码)
也可以从中获取出更多的使用方式(JsonResponse)
"""
切入口是: form_obj.is_valid()
def is_valid(self):
"""
Returns True if the form has no errors. Otherwise, False. If errors are
being ignored, returns False.
"""
return self.is_bound and not self.errors
# 只要给类传参self.is_bound肯定就是True
@property
def errors(self):
if self._errors is None:
self.full_clean()
return self._errors
# 查看了源码发现self._errors初始化就是None 所以肯定走full_clean方法
# 查看源码发现校验数据的整个过程内部都有异常处理机制
# 主动报异常
from django.core.exceptions import ValidationError
raise ValidationError('用户不存在,去注册,要不然给你刀了')
modelform组件
"""
我们学习校验组件的目的 绝大部分是为了数据录入数据库之前的各项审核
forms组件使用的时候需要对照模型类编写代码 不够方便
"""
forms组件的强化版本 更好用更简单更方便
'''models 层'''
class UserInfo(models.Model):
username = models.CharField(max_length=32, verbose_name='用户名')
age = models.IntegerField(verbose_name='年龄')
'''view 层'''
from django import forms
from app01 import models
class MyModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo
fields = '__all__'
labels = {'username': '用户名'}
def ad_index_func(request):
modelform_obj = MyModelForm()
if request.method == 'POST':
modelform_obj = MyModelForm(request.POST)
if modelform_obj.is_valid():
"""
这个save 就相当于 models.UserInfo.objects.create()
或
models.UserInfo.objects.update()
"""
modelform_obj.save()
else:
print(modelform_obj.errors)
return render(request, 'indexPage.html', locals())
'''html'''
<form action="" method="post" novalidate>
{% for foo in modelform_obj %}
<p>{{ foo.label }}
{{ foo }}
{{ foo.errors.0 }}</p>
{% endfor %}
<input type="submit" name="" id="">
</form>
django中间件
django默认有七个中间件 并且还支持用户自定义中间件
中间件主要可以用于:网站访问频率的校验 用户去权限的校验等全局类型的功能类型
# 中间件
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
如何自定义中间件
如何自定义中间件
1.创建存储自定义中间件代码的py文件或者目录(如果中间件很多)
2.参考自带中间件的代码编写类并继承
3.在类中编写五个可以自定义的方法
需要掌握的
process_request
1.请求来的时候会从上往下依次经过每一个注册了的中间件里面的该方法 如果没有则直接跳过
2.如果该方法自己返回了HttpResponse对象那么不再往后执行而是直接原路返回
process_response
1.响应走的时候会从下往上依次经过每一个注册了的中间件里面的该方法 如果没有则直接跳过
2.该方法有两个先request和response 形参response指代的就是后端想要返回给前端浏览器的数据 该方法必须返回该形参 也可以替换
'''如果在执行process_request方法的时候直接返回了HttpResponse对象那么会原路返回执行process_response 不是执行所有'''
需要了解的
process_view
process_exception
process_template_response
4.一定在配置文件中注册中间件才可以生效
分类:
django
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?