内部解析机制
我们的Django框架或者html" class="superseo">ajax内部都有一个json的解析机制,可以帮助我们解析json数据,让我们省去使用json.dumps或者JSON.parse等方法进行相应的解析。
- ajax的js解析机制
views函数:
通过HttpResponse给前端响应数据时,加上一个content_pe='application/json'这样的头部键值对
return HttpResponse(ret_dict_json, content='application/json')
ajax:
获得res直接就是一个object对象(字典),因为通过这个头部可以调用ajax的json内部解析机制对其进行解析,省去了JSON.parse(res)这个环节。
- Django的json解析机制
from django.http import JsonResponse
# JsonResponse 将一个数据内部转化成Json的格式,响应给前端
# 这样我们就省去了json.dumps这个环节
ret_dict = {'code':0, 'content': '用户名或者密码错误'}
return JsonRespone(ret_dict)
- 尝试一个列表
html:
{% load static %}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initialscale=1">
<title>Bootstrap 101 Template</title>
</head>
<body>
<h3>欢迎来到ajaxlx⾸⻚</h3>
<ul>
</ul>
</body>
<script src="{% static 'jQuery.js' %}"></script>
<script>
$.ajax({
url: "{% url 'data' %}",
type: 'get',
success: function (res) {
{#console.log(res, typeof res)# }
{#var li = '<li>' + res + '</li>'# }
$.each(res, function (k, v) {
var li = '<li>' + v + '</li>';
$('ul').append(li)
})
}
})
</script>
</html>
views函数:
def ajax_lx(request):
return render(request, 'lx.html')
def data(request):
l1 = ['姓名1', '姓名2', '姓名3']
# 我们通过网络传输数据一般都是字段类型,前端教object类型。
#In order to allow non-dict objects to be serialized set the safe
parameter to False.
return JsonResphonse(l1, safe=False)
url:
url(r'^ajaxlx/', views.ajax_lx,name='ajaxlx'),
url(r'^data/', views.data,name='data'),
content-type
这个参数比较重要,这个参数是请求头部信息中,非常重要的参数,这个参数是标明请求参数的数据类型。
- content-type = application/x-www-form-urlencoded
我们简称encoded类型,一般前端给后端发送数据(get。post),form、ajax等方式默认一般都是encoded类型。
通过ajax提交数据:
通过form表单提交:
这种类型的原始数据是神样子的?
无论是ajax还是form(无论是get还是post)或者其他方式,只要是encoded类型,原始数据都是:
键=值&键=值&键=值...
为什么浏览器会同意这种格式?
浏览器统一了请求数据的格式,便于后端做归一化处理。
看我们的Django后端:
为什么我们通过request.POST.get(键)或者request.GET.get(键)就可以获取该值?
就是因为Django的内部解析器帮助我们做了请求数据的解析:
举例:
Django的内部做了一个这样的判断:
if 'content_type' == 'application/x-www-form-urlencoded':
'''uname=taibai&pwd=123&csrfmiddlewaretoken=oTRcxqSxLGSygOSaMrqyiakOXJIgbM
CBVAESFZ1dqK8ttsHL9maoI9wzLEyfYcaI
'''
通过&分割,然后在通过等号分割,然后构建到request.POST或者request.GET中,最终我们可以通过get方法获取到对应值。
- content_type = application/json
Django框架默认不认可这种类型,这就意味着,如果我们与其他的一些程序员或者一些语言写的项目对接数据,这就叫做数据接口,一般这种数据接口都是使用这种数据类型。content_type = application/json类型
验证一下:
这样我们就构建了以application/json的类型的json数据,发送到Django框架的后端。
后端默认取不到对应的值,返回的是None
只能通过:
request.get_full_path() # 获取原始数据
这样我们只能自己完成数据的分割以及获取
我们通过request.META获取conten_type内容,判断如果是application/json类型我们自己在后端对request.get_full_path()进行数据切割,从而获取数据。但是这样给我们增加了开发难度,降低开发效率。这种情况下,有一个第三方模块:*前后端分离的模块,djangorestframework
- content_type = mutipart/form-data类型
给Django后端发送的请求数据为文件(文本、图片、视频、音频等等),是这种类型,
Django内部解析器可以帮我们解析。
(下面综合文件上传一起)
文件上传
- form表单
def form_upload(request):
if request.method == 'GET':
return render(request, 'formupload.html')
else:
# print(request.POST)
'''
<QueryDict: {'csrfmiddlewaretoken':
['8FUYSNC9tTfsVpGzHSJlz7s7Lkko1U12FmHE0mLP8Xvn83va4NtbZ6ESzfanOkz9'],
'head_pic': ['barry.png'],
'ID': ['1232321321321321']}>
'''
# print(request.POST.get('ID'))
# ret = request.POST.get('head_pic') # 获取了⽂件的⽂件名
# print(ret, type(ret))
# file = request.FILES # <MultiValueDict: {}>
# 为什么是空?因为from表单没有规定enctype属性
# < MultiValueDict: {'head_pic': [ < InMemoryUploadedFile: barry.png(image / png) >]} >
# 这个文件数据是一个迭代器,类似于文件的文件句柄
# print(file)
# file_obj = request.FILES.get('head_pic')
# print(file_obj) # 返回的是名字 因为__str__返回的是名字
# print(file_obj.name) # 获取的是名字
file_obj = request.FILES.get('head_pic')
from ajac_online import settings
import os
img_path = os.path.join(settings.BASE_DIR,'statics','img')
# 方式1:
# with open(os.path.join(img_path, file_obj.name), mode='wb') as fp:
# for line in file_obj:
# 默认按照行去循环,以换行符/r/n为循环节点
# fp.write(line)
# 方式2:
with open(os.path.join(img_path, file_obj.name), mode='wb') as fp:
for chunk in file_obj.chunks():
f1.write(chunk)
return redirect('formupload')
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap 101 Template</title>
</head>
<body>
<h1>form表单⽂件上传</h1>
<form action="" method="post" enctype="multipart/form-data">
{# 这个属性就是规定的content_type类型 #}
{% csrf_token %}
头像:<input type="file" name="head_pic">
<p></p>
身份证:<input type="text" name="ID">
<p></p
- 自己写的:
url:
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^wenjianshagnchuan1/', views.shangchuan1, name='file_sc_form')
]
html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>form表单文件上传</h1>
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
文件:<input type="file" name="file_form_sc">
<p></p>
ID:<input type="text" name="ID">
<p></p>
<input type="submit">
</form>
</body>
</html>
views:
def shangchuan1(request):
if request.method == 'GET':
return render(request, 'file_sc.html')
else:
file_obj = request.FILES.get('file_form_sc')
import os
from ajax_practice1 import settings
# 注意:需要提前在静态文件夹里面创建好 images 文件夹
img_path = os.path.join(settings.BASE_DIR, 'jingtaiwenjian', 'images')
with open(os.path.join(img_path, file_obj.name), mode='wb') as fp:
for chunk in file_obj.chunks():
fp.write(chunk)
print(file_obj.name, '保存完成!')
return redirect('file_sc_form')
- ajax文件上传
1、重新启动一个流程
2、构建代码
url:
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^wenjianshangchuan2/', views.shangchuan2, name='file_sc_ajax'),
]
views:
from django.shortcuts import render, redirect, HttpResponse
from django.views import View
import json
def shangchuan2(request):
if request.method == 'GET':
return render(request, 'file_sc_ajax.html')
else:
print(request.POST)
print(request.POST.get('ID'))
print(request.FILES)
print(request.FILES.get('file_ajax_sc'))
html:
{% load static %}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>ajax文件上传</h1>
</body>
<div>
{% csrf_token %}
文件:<input type="file" id="file_ajax_sc">
<p></p>
ID: <input type="text" id="ID">
<p></p>
<input type="button" value="提交" id="btn">
</div>
<script src="{% static 'jquery-3.5.1.js' %}"></script>
<script>
$('#btn').click(
function () {
$.ajax(
{
url: "{% url 'file_sc_ajax' %}",
type:'post',
data:{
file_ajax_sc: $('#file_ajax_sc').val(),
ID : $('#ID').val(),
csrfmiddlewaretoken: '{{ csrf_token }}'
},
success : function (res) {
console.log(res)
}
}
)
}
)
</script>
</html>
上面这种方式。只能提交非文件的数据,不能提交文件类的数据
3、重构代码
- 如何获取文件数据
通过之前的构建方式,你只是获取了文件的路径,而并没有文件的数据。
jQuery对象与DOM对象的互相转换
jQuery对象 ——》 DOM对象:
$('')[0]
DOM对象 ——》 jQuery对象
$(DOM)
DOM对象.files 返回文件列表
views代码:
def shangchuan2(request):
if request.method == 'GET':
return render(request, 'file_sc_ajax.html')
else:
file_obj = request.FILES.get('file_ajax_sc')
import os
from ajax_practice1 import settings
img_path = os.path.join(settings.BASE_DIR, 'jingtaiwenjian', 'images')
print(img_path)
with open(os.path.join(img_path, file_obj.name), mode='wb') as fp:
for chunk in file_obj.chunks():
fp.write(chunk)
print(file_obj.name, '保存完成!')
return HttpResponse('请求成功')
html:
{% load static %}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>ajax文件上传</h1>
</body>
<div>
{% csrf_token %}
文件:<input type="file" id="file_ajax_sc">
<p></p>
ID: <input type="text" id="ID">
<p></p>
<input type="button" value="提交" id="btn">
</div>
<script src="{% static 'jquery-3.5.1.js' %}"></script>
<script>
$('#btn').click(
function () {
var formdata = new FormData();
formdata.append('ID', $('#ID').val());
formdata.append('file_ajax_sc', $('#file_ajax_sc')[0].files[0]);
formdata.append('csrfmiddlewaretoken','{{ csrf_token }}');
$.ajax(
{
// 要通过ajax上传文件数据必须借助于formdata对象进行上传
url: "{% url 'file_sc_ajax' %}",
type:'post',
data : formdata,
processData: false, // 不处理数据
contentType: false, // 设置数据类型
success : function (res) {
console.log(res)
}
}
)
}
)
</script>
</html>
settings配置文件
项目中的settings是Django提供给用户进行配置的,删掉settings默认配置的某些元素,你的整个项目是不影响的。为什么?
Django的源码中有一个框架的内部settings。启动项目,先加载给用户设置的settings文件,然后再加载源码中的内置的settings文件。
from django.conf import settings
按住ctrl+鼠标点击settings。然后在ctrl+鼠标单击global_settings
如果想要更改全局的settings,你可以直接更改在全局settings里面更改,也可以在用户的settings里面复制更改。
json的回顾
json是一个语言,但是他更像是一个公认的转换格式。所有语言都支持的一种转化格式。
python中的set集合,就不能发送给js,因为json就不可能让你set序列化。
带来的我呢提,前端和后端会经常交互一些时间数据,pthon有date以及datetime类型,jsono中没有响应的数据,默认i情况下,后端要想给前端发送一个date或者datetime类型的数据,是发送不出去的。
测试:
import json
from datetime import datetime
from datetime import date
class JsonCustomEncoder(json.JSONEncoder):
def default(self, field):
if isinstance(field, datetime):
return field.strftime('%Y-%m-%d %H:%M:%S')
elif isinstance(field, date):
return field.strftime('%Y-%m-%d')
else:
return json.JSONDecodeError.default(self, field)
ret = {'name': 'dong', 'birthday': datetime.now()}
dd = json.dumps(ret, cls=JsonCustomEncoder)
print(dd)
http协议回顾
http是超文本传输协议,浏览器与服务端进行数据通信要遵循的协议。
http协议有三个特点:基于请求与响应,无连接,无状态
- 什么是会话?
http协议是不支持绘画的这种模式的。因为http是无连接无状态的。
- 无连接
无连接(短连接),浏览器请求一个页面,与服务端建立一个连接,服务端收到请求返回给浏览器一个页面,连接断开。为什么要断开?建立一个连接服务端要开启一个线程处理,非常耗费资源,最早都是无连接的,现在有的可以设置为短链接,建立连接之后,保持一段时间,默认是3秒钟,这个时间你可以控制。
浏览一个网站用户会保持一段时间,在这个时间之内,保持连接比断开在连接效率要高一些。
- 无状态
一个用户访问一个网站,通过http协议,那么http协议不会记住你这个用户的信息,你链接一次断开了,再次连接,http不会记住你。这激素和i无状态。
- 带来的影响:
比如我们访问淘宝,当你想访问购物车时,先登录,在访问,然后访问收藏夹的时候,还得登录,才能访问,在访问其他界面,还得先登录...
这样用户体验感好不好?
肯定不好,你如果想完成访问你的网站,登录一次之后,网站所有的页面都可以访问了这样的需求,这样http协议完不成了,你需要借助cookie与sesstion了。