day06 form组件
昨日内容复习
ajax实现二次确认 #原生js
1.按钮绑定点击事件
2.判断是否发送ajax请求
数据携带方式注意
#进阶版 引用第三方插件sweetalert
1.给按钮绑定点击事件
2.赋值插件代码
3.修改部分内容
#前后端交互使用ajax 那么后端推荐返回字典类型的json格式字符串
ajax发送文件数据 先要获取input框用户上传的文件数据 如果获取多个数据 最后面的索引0不需要加
# 其实$('#d1')[0] ==转成原生js对象
两种方式1.用jquery版本
$('#d1')[0].files[0]
第二种方式使用js代码
document.getElementById('d1').files[0]
#js内置对象FormData
产生一个form对象
对象.append('别名',获取数据的values)
formDataObj.append('name',$('#d2').val())
#发送文件需要额外配置的两个参数contentType,processData
contentType: false, #这块注意发送json格式数据要写成'application/json'相当于报头
processData: false,
data:formdata对象
datetype参数 后端使用HttpResponse返回的json格式字符串 ,他会自动反序列化成js格式对应的数据类型
后端使用JsonResponse返回的json格式字符串 ,他加不加都行
语法格式:dataType:'JSON' 指定后 后端返回给前端的数据如果不是json格式的 他不会反序列化 会自动区分是不是json格式的
# 以后推荐加上 增加程序兼容性
序列化组件 from django.core import serializers
#serializers.serializer 直接可以把 queryset列表套数据对象 转换成json格式的列表套字典 字典里自动加来自于哪个应用下的那个表,主键值 ,表的字段用一个fields做一个字典嵌套 外键什么的也会放在一个字典里
res=serializers.serialize('json',books_queryset) #books_queryset里面有很多很多数据对象
return HttpResponse(res)
序列化其实就是将数据组织成字典并序列化成json格式的过程
from django.core import serializers
批量插入(bulk_create) 当需要频繁的插入大量数据的时候可以考虑是该方法 能够极大地提升效率
#生成器表达式 生产一个new_obj_iter里面存放了好多好多对象对象里面存了 title这个属性
new_obj_iter=(models.Book(title='第%s本书'%i) for i in range(100000))
#批量插入bulk_create
models.Book.objects.bulk_create(new_obj_iter)
分页 # queryset支持索引和切片[0,10] 索引0开始到10
1.需要数据的总量
2.需要定义每页展示多少条
3.需要计算总共需要多少页
4.需要推导出几个核心参数的数学关系
5.需要后端生成html代码
1.前端传给后端要看第几页数据 后端获取请求的页数
2.后端定义页面显示多少数据 起始位置 终止位置 他们是有逻辑关系的
3.后端通过divmod 获取总共多少页 有余数+1
4.后端定义 一个变量=当前页数 判断当前选择的页数小于最小页的中间位置 让这个变量=最小页的中间位置 为了防止左面越界 右面的也设置
5.后端编写HTML代码 for循环 开始位置-5 结束为止+6 设置超链接 并且选择的列高亮显示
6.前端接受数据 for循环数据对象 取title 加上一个分页器bootstrap 引用后面的html代码 实现显示十页
今日内容概要
form组件
是modelform组件的前身 功能更加强大 学完drf再学更容易接受
今日内容详细
form组件前言
low 版本校验
def myform(request):
error_dict={'User_msg':'','Pwd_msg':''}
if request.method=='POST':
username= request.POST.get('username')
password=request.POST.get('password')
if username=='zhang':
error_dict['User_msg']='名字不能是zhang'
if len(password)==0:
error_dict['Pwd_msg']='密码不能为空'
return render(request,'myform.html',locals())
前端需要后面加一个span标签 里面引用后端的error_dict的里面的User_msg 或者Pwd_msg 实现了校验
自定义数据校验功能 主要步骤
1.搭建前端页面 标签渲染
2.校验数据是否合法 数据校验
3.返回相应的提示信息 提示信息
form组件可以自动实现
form组件基本定义
与models定义类基本一致
但是这里定义在views视图层
1.先导入
from django import forms
2.定义
class MyFormWow(forms.Form):
#username字段最长8位,最短3位
username=forms.CharField(max_length=8,min_length=3)
# password字段最长8位,最短3位
password=forms.CharField(min_length=3,max_length=8)
# email字段必须符合邮箱格式 可以为空
email=forms.EmailField(required=False))
form组件数据校验功能
#导入模块
from app01 import views
#1传入待校验的数据
obj=views.MyFormWow({'username':'zhang','password':'123','email':'123@q.com','hobby':'111'})
#2.判断所有的数据是否合规
print(obj.is_valid()) #结果为布尔值 (只有所有的数据都合规才返回True)
#3.查看符合点击校验的数据
print(obj.cleaned_data) #结果为字典 所有通过校验的数据
#4.如何查看不符合条件校验的数据
print(obj.errors) #返回错误字段和错误原因
"""
1.在传递数据的时候 如果多传了额外字段 没有关系 form不校验 不理这个多传入的字段
2.form组件内部定义的字段数据 默认都是必填的
可以通过修改参数required=False来控制是否必填 默认=True 必填
"""
form组件渲染标签功能
#从新添加一个urls 路由关系 my_form 里面创建一个myform对象 返回给前端界面
def my_form(request):
obj=MyFormWow()
return render(request,'my_form.html',locals())
"""
#自动渲染出在定义类时候 需要用户传的数据对应的标签
自动渲染的标签文本名称默认采用字段名首字母大写的形式
可以通过label参数自定义名称
form只渲染获取用户数据的标签 不渲染提交按钮 需要我们自己编写
"""
#前端界面 渲染标签方式1 封装程度高 不容易扩展 一般用于本地测试
{{ obj.as_p }} #自动生成 字段名字后面跟个输入框
{{ obj.as_ul }} #自动生成 无序 用ul里面的li包裹
{{ obj.as_table }} #自动生成 在一行
#渲染标签方式2 扩展性高 书写麻烦
'''
obj.username.label:获取label值
obj.username.id_for_label:获取输入框的id值 这个实现了点前面这个label 光标跳到后面的输入框
obj.username :该输入框
'''
<div>
<label for="{{ obj.username.id_for_label }}">{{ obj.username.label }}</label>
{{ obj.username }}
</div>
<div>
<label for="{{ obj.password.id_for_label }}">{{ obj.password.label }}</label>
{ obj.password }}
</div>
<div>
<label for="{{ obj.email.id_for_label }}">{{ obj.email.label }}</label>
{{ obj.email }}
</div>
#渲染标签方式3 融合了方式1和方式2的优势(推荐使用) 书写简单 易扩展
{% for foo in obj %} #for循环一次就拿这个对象的类的字段一次 .参数的形式拿值
<p>
<label for="{{ foo.id_for_label }}">{{ foo.label }}</label>
{{ foo }}
</p>
{% endfor %}
form组件数据提示信息功能
#前端校验 可有可无
在form表单加上一个novalidate 意思是不让前端校验,让后端校验
<form action="" method="post" novalidate>
#发过来的数据后端获取
def my_form(request):
obj=MyFormWow()
if request.method=='POST':
#直接将数据传入类中
obj=MyFormWow(request.POST)
#判断数据是否合规
if obj.is_valid():
print(obj.cleaned_data)
else:
print(obj.errors)
#不管是post get请求最后都会返回 get请求返回的是一个空的obj ,post 返回的是有正常信息,错误信息的obj
return render(request,'my_form.html',locals())
#错误信息前端也可以显示span标签 有值显示 没值不显示 不占空间 .0是让他只显示文本
<span style="color: red">{{ foo.errors.0 }}</span>
# 后端自定义提示信息 error_messages 在类定义时候使用 还有一种方式 settings字符编码里面LANGUAGE_CODE='zh-hans' 改成中文
error_messages={
'max_length':'用户名最多8位',
'min_length':'用户名最少3位',
'required':'用户名不能为空' #不能为空
}
邮箱的错误有一点不一样
error_messages={
'required': '邮箱不能为空',
'invalid':'邮箱格式不正确' #这个参数邮箱格式的
}
form组件进阶
数据校验--正则校验
#先导入模块
from django.core.validators import RegexValidator
定义一个新的字段
phone=forms.CharField(label='手机号',
validators=[RegexValidator(r'^[0-9]+$', '请输入数字'),
RegexValidator(r'^159[0-9]+$', '数字必须以159开头')
],
)
#钩子函数 分为局部钩子 和全局钩子 前面基本校验规则执行之后才会执行钩子函数 顺序为 mix_length参数校验--validators正则校验--钩子函数
#局部钩子 钩一些数据 校验单子字段 校验用户名是否已存在 在定义类时候写好 写个方法
def clean_username(self): #
#1.获取用户名数据 在已经校验完的数据找
username=self.cleaned_data.get('username')
#2.校验用户名是否已存在
if username=='zhang':
#2.1存在添加用户名存在信息
self.add_error('username','用户名已存在')
#3.返回勾出来的数据
return username
#全局钩子 校验第一次输入的密码和第二次输入的是否一致 名字只能交clean
def clean(self):
password=self.cleaned_data.get('password')
confirm_password=self.cleaned_data.get('confirm_password')
if not password==confirm_password:
self.add_error('confirm_password','两次输入密码不一致')
return self.cleaned_data #全局数据返回
form组件
#参数部分
label 字段名称
required 是否必填 True必填 False非必填 默认True
initial 默认值
error_messages 自定义错误信息
widget 修改标签的属性 比如type class 等
widget=forms.widgets.PasswordInput() #修改type
widget=forms.widgets.TextInput(attrs={'class':'form-control'}) #修改什么属性写什么用字典的形式
#一些不常用的
在使用选择标签时,需要注意choices的选项可以配置从数据库中获取,但是由于是静态字段 获取的值无法实时更新,需要重写构造方法从而实现choice实时更新。获取数据库的值给choise赋值
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')
#单选框
gender = forms.fields.ChoiceField(
choices=((1, "男"), (2, "女"), (3, "其他")),
label="性别",
initial=1,
widget=forms.widgets.RadioSelect()
)
#单选框radioSelect
hobby = forms.ChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
label="爱好",
initial=3,
widget=forms.widgets.Select()
)
#多选框Select
hobby1 = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
label="爱好",
initial=[1, 3],
widget=forms.widgets.SelectMultiple()
)
#单选checkbox
keep = forms.ChoiceField(
label="是否记住密码",
initial="checked",
widget=forms.widgets.CheckboxInput()
)
#多选checkbox
hobby2 = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.CheckboxSelectMultiple()
)
#这几个不常用的前端如图显示
form组件源码
"""阅读源码是提升编程思维的最佳方式!!!"""
突破口is_valid