Django请求生命周期
前后端数据交换
一般的编码格式
1、urlencoded
2、formdata
3、application/json
form表单编码格式
form表单默认的编码格式是urlencoded不支持发文件(只能把文件名发过去)
它所对应数据格式 username=jason&password=123
formdata
request.POST只能解析urlencoded数据格式的数据
formdata django会帮你把文件数据取出来 放入request.FILES里面 专门用来传文件的
.html
<form action="" method="post" enctype="multipart/form-data"> //注意enctype
{% csrf_token %}
username: <input type="text" name="username"><br>
password: <input type="password" name="password"><br>
img: <input type="file" name="myfile"><br>
<input type="submit" value="提交">
</form>
view.py
file_obj = request.FILES.get('myfile')
print(file_obj.name) # 查看当前文件对象的文件名
with open(file_obj.name,'wb') as f:
for line in file_obj:
f.write(line)
AJAX
Ajax默认提交的编码格式也是urlencoded
当用ajax传输json格式的数据时候 django不会做任何处理
数据以二进制形式放在request.body中 你可以手动解码加反序列化拿到对应的字典格式数据
bytes_str = request.body
res = json.loads(bytes_str.decode('utf-8'))
print(res,type(res))
jax发送文件 利用js内置的FormData对象
<input type="file" name="myfile" id="d2">
<button id="d1">点我</button>
$('#d1').click(function () {
// 如果用ajax发送文件 需要使用内置对象FormData
var formData = new FormData(); // 生成一个内置对象
// 内置对象formdata既可以传普通的键值对,也可以传文件
formData.append('name','jason'); // 普通键值对
formData.append('password','123');
// 传文件
var fileObj = $('#d2')[0].files[0]; // 先获取标签对象 转成原生js对象 通过内置的files方法拿到所有的文件对象列表 然后去索引0拿到文件对象
formData.append('myfile',fileObj);
$.ajax({
url:'', // 不写默认朝当前页面所在的url地址提交
type:'post',
// 注意ajax在发送文件的时候 需要你手动指定两个特殊的参数,这两个必须写
contentType:false, // 不要用任何编码 使用我formdata自带的编码即可
processData:false, // 浏览器不要处理我的数据 是什么就什么
data:formData,
success:function (data) {
alert(data)
}
})
})
forms组件
forms组件的3个过程
1.前端渲染展示页面 获取用户输入 >>> 渲染页面
2.将数据发送给后端进行数据的合法性校验 >>> 数据校验
3.将不合法的提示信息展示给用户看 >>> 展示提示信息
关于数据的校验
1.前端
2.后端
数据的校验前端可以没有,但是后端一定要做!!!
自己写一个前后端校验的例子
.html
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
username: <input type="text" name="username">
<span>{{ back_dic.flag }}</span>
<br>
password: <input type="password" name="password">
<span>{{ back_dic.msg }}</span>
<br>
img: <input type="file" name="myfile"><br>
<input type="submit" value="提交">
</form>
views.py
def index(request):
if request.method == 'POST':
# file_obj = request.FILES.get('myfile')
# print(file_obj.name)
# print(request.body)
back_dic = {"flag":'',"msg":''}
username = request.POST.get('username')
password = request.POST.get('password')
if not username:
back_dic['flag'] = "账户不能为空"
if len(password) < 6:
back_dic['msg'] = "密码太短"
return render(request,"inddex.html",locals()) //将函数内的名称空间全部传过去
forms组件校验数据
1.校验数据
forms组件的校验数据的使用
1.定义一个继承forms.Form一个类
from django import forms
class MyForm(forms.Form):
username = forms.CharField(max_length=6) # username最长只能是6位
password = forms.CharField(max_length=8,min_length=3) # password最长8位 最短3位
email = forms.EmailField() # email接受的数据必须符合邮箱格式
完整版
# 使用forms组件第一步需要你手动写一个类 并且要继承forms.Form
from django import forms
from django.forms import widgets # 当你用forms点widgets点不出来的时候 自己手动导入一下
from django.core.validators import RegexValidator
class MyForm(forms.Form):
username = forms.CharField(max_length=6,label='用户名',initial='我是最帅的',error_messages={
'max_length':'用户名最长6位',
'required':'用户名不能为空'
}) # username最长只能是6位
password = forms.CharField(max_length=8,min_length=3,label='密码',
widget=widgets.PasswordInput(attrs={'class':'form-control c1',})
) # password最长8位 最短3位
confirm_password = forms.CharField(max_length=8, min_length=3, label='确认密码',
widget=widgets.PasswordInput(attrs={'class': 'form-control c1', })
) # password最长8位 最短3位
phone = forms.CharField( validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],)
email = forms.EmailField(label='邮箱',error_messages={
'required':'邮箱不能为空',
'invalid':'邮箱格式不正确'
}) # email接受的数据必须符合邮箱格式
forms组件中所有的字段默认都是必填的(不能为空)
在数据都满足forms组件校验规则的情况下 多传的数据不校验 没有关系
gender = forms.fields.ChoiceField(
choices=((1, "男"), (2, "女"), (3, "保密")),
label="性别",
initial=3,
widget=forms.widgets.RadioSelect()
)
hobby = forms.ChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=3,
widget=forms.widgets.Select()
)
hobby1 = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.SelectMultiple()
)
keep = forms.ChoiceField(
label="是否记住密码",
initial="checked",
widget=forms.widgets.CheckboxInput()
)
2.给forms组件传参数 (字典的显示)
obj = views.MyForm({'username':'egondsb','password':'12','email':'123@qq.com'})
3.查看数据是否完全合法
obj.is_valid()
4.查看所有校验通过的数据
obj.cleaned_data
{'email': '123@qq.com'}
5.查看所有没有通过的数据
obj.errors
"""
{
'username': ['Ensure this value has at most 6 characters (it has 7).'],
'password': ['Ensure this value has at least 3 characters (it has 2).']}
"""
2.渲染标签
forms组件只能帮你渲染 获取用户输入(输入框 选择框 下拉框...)的标签
提交按钮也得自己写
form表单取消前端校验功能
<form action="" method="post" novalidate>
forms组件当前端输入的信息不合法的时候 页面上的数据保留不会刷新 这样方便用户修改
3.展示提示信息
{% for foo in form_obj %}
<p>
{{ foo.label }}{{ foo }}
<span>{{ foo.errors.0 }}</span>
</p>
{% endfor %}
forms组件的钩子函数
# 局部钩子
def clean_username(self):
# 用户名中不能有666
username = self.cleaned_data.get('username')
if '666' in username:
self.add_error('username','光喊666是不行的')
return username
# 全局钩子
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
django代码测试
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day66.settings")
import django
django.setup()
from app01 import models
print(models.Userinfo.objects.all())