昨日内容回顾
基于对象的跨表查询
正向查询:关联属性在A表中,所以A对象找关联B表数据,正向查询
反向查询:关联属性在A表中,所以B对象找A对象,反向查询
一对多:
按字段:xx
book ------------------ > publish
<--------------------
按表名小写__字段名。比如publish__name
多对多:
正 按字段:xx
book ------------------------- > author
<-------------------------
反 按表名小写__字段名
一对一
正 按字段:.ad
author ------------------------- > authordetail
<-------------------------
反 按表名小写 authordetail_obj.author
一、Django与Ajax
AJAX准备知识:JSON
什么是 JSON ?
- JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
- JSON 是轻量级的文本数据交换格式
- JSON 独立于语言 *
- JSON 具有自我描述性,更易理解
- JSON 使用 JavaScript 语法来描述数据对象,但是 JSON 仍然独立于语言和平台。JSON 解析器和 JSON 库支持许多不同的编程语言。
合格的json对象:
["one", "two", "three"]
{ "one": 1, "two": 2, "three": 3 }
{"names": ["张三", "李四"] }
[ { "name": "张三"}, {"name": "李四"} ]
不合格的json对象:
{ name: "张三", 'age': 32 } // 属性名必须使用双引号
[32, 64, 128, 0xFFF] // 不能使用十六进制值
{ "name": "张三", "age": undefined } // 不能使用undefined
{ "name": "张三",
"birthday": new Date('Fri, 26 Aug 2011 07:13:10 GMT'),
"getName": function() {return this.name;} // 不能使用函数和日期对象
}
json支持7种数据格式
python 原始类型向 json 类型的转化对照表:
Python | JSON |
---|---|
dict | object |
list, tuple | array |
str, unicode | string |
int, long, float | number |
True | true |
False | false |
None | null |
stringify与parse方法
JavaScript中关于JSON对象和字符串转换的两个方法:
JSON.parse(): 用于将一个 JSON 字符串转换为 JavaScript 对象
JSON.parse('{"name":"Q1mi"}');
JSON.parse('{name:"Q1mi"}') ; // 错误
JSON.parse('[18,undefined]') ; // 错误
JSON.stringify(): 用于将 JavaScript 值转换为 JSON 字符串。
JSON.stringify({"name":"Q1mi"})
和XML的比较
JSON 格式于2001年由 Douglas Crockford 提出,目的就是取代繁琐笨重的 XML 格式。
JSON 格式有两个显著的优点:书写简单,一目了然;符合 JavaScript 原生语法,可以由解释引擎直接处理,不用另外添加解析代码。所以,JSON迅速被接受,已经成为各大网站交换数据的标准格式,并被写入ECMAScript 5,成为标准的一部分。
XML和JSON都使用结构化方法来标记数据,下面来做一个简单的比较。
用XML表示中国部分省市数据如下:
<?xml version="1.0" encoding="utf-8"?>
<country>
<name>中国</name>
<province>
<name>黑龙江</name>
<cities>
<city>哈尔滨</city>
<city>大庆</city>
</cities>
</province>
<province>
<name>广东</name>
<cities>
<city>广州</city>
<city>深圳</city>
<city>珠海</city>
</cities>
</province>
<province>
<name>台湾</name>
<cities>
<city>台北</city>
<city>高雄</city>
</cities>
</province>
<province>
<name>新疆</name>
<cities>
<city>乌鲁木齐</city>
</cities>
</province>
</country>
用JSON表示如下:
{
"name": "中国",
"province": [{
"name": "黑龙江",
"cities": {
"city": ["哈尔滨", "大庆"]
}
}, {
"name": "广东",
"cities": {
"city": ["广州", "深圳", "珠海"]
}
}, {
"name": "台湾",
"cities": {
"city": ["台北", "高雄"]
}
}, {
"name": "新疆",
"cities": {
"city": ["乌鲁木齐"]
}
}]
}
由上面的两端代码可以看出,JSON 简单的语法格式和清晰的层次结构明显要比 XML 容易阅读,并且在数据交换方面,由于 JSON 所使用的字符要比 XML 少得多,可以大大得节约传输数据所占用得带宽。
Ajax简介
AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML,现在更多使用json数据)。
- 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
- 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。
AJAX除了异步的特点外,还有一个就是:浏览器页面局部刷新;(这一特点给用户的感受是在不知不觉中完成请求和响应过程)
应用情景
搜索引擎根据用户输入的关键字,自动提示检索关键字。
还有一个很重要的应用场景就是注册时候的用户名的查重。
其实这里就使用了AJAX技术!当文件框发生了输入变化时,使用AJAX技术向服务器发送一个请求,然后服务器会把查询到的结果响应给浏览器,最后再把后端返回的结果展示出来。
- 整个过程中页面没有刷新,只是刷新页面中的局部位置而已!
- 当请求发出后,浏览器还可以进行其他操作,无需等待服务器的响应!
比如博客园的注册页面:
直接点击注册,相关的输入框就会有提示。这些就是利用局部刷新做到的!
输入框绑定了blur事件(当输入完用户名以后触发动作)
优点:
- AJAX使用Javascript技术向服务器发送异步请求
AJAX无须刷新整个页面
简单来说,1.异步请求。2.局部刷新
Ajax流程图
1、客户端触发异步操作
2、创建新的XMLHttpRequest对象,这是ajax的核心(需要着重的学习下)
3、通过send()方法实现与server的连接4
4、服务器端接收请求,并处理
5、返回处理的结果,这个结果可以是XML文档、也可以是josn字符串(一般情况下josn就可以处理大部分的结果、而且相对的比较好操作)
6、在客户端去接收服务器传回来的结果,并且通过javascript进行你想要的处理
发请求给服务器的途径:
地址栏:get
form表单,支持get和post
超链接 click 这种是get方式
Ajax请求: 可以指定get和post
发Ajax请求一般返回httpResponse()
案例
鼠标点击事件
效果:当点击click时,弹出提示框
准备工作:
使用Pycharm新建项目ajaxDemo
修改urls.py,增加路径index
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
]
修改views.py,增加index视图函数
def index(request):
return render(request,"index.html")
在创建index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script scr="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<button id="btn">click</button>
<script>
$("#btn").click(function () {
alert(123)
})
</script>
</body>
</html>
启动django项目,访问url:http://127.0.0.1:8000/index/
点击click,就会出现弹框
简单的ajax请求
效果:当点击click时,按钮底部出现一本书名
修改urls.py,增加books路径
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
path('books/', views.books),
]
修改books视图函数
def books(request):
return HttpResponse("群山淡景")
修改index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<button id="btn">click</button>
<p class="con"></p>
<script>
$("#btn").click(function () {
//发送ajax请求
$.ajax({
url:"/books/", //请求的url
type:"get", //默认get
success:function (data) { //data接收响应体,必须要有
console.log(data); //打印响应体数据
$(".con").text(data); //修改p标签的text值
}
})
})
</script>
</body>
</html>
访问url:点击click按钮,底部出现一本书
那么,它经历了怎样的过程呢?请参考上面的ajax流程图!
success表示请求成功,并拿到响应体之后,执行的动作!data是用来接收响应体的数据。data这个命令可以随便定义,约定成俗,使用data!
它接收HttpResponse,比如:《群山淡景》
最后是dom操作,修改HTML代码,实现了局部刷新!
ajax加法运算(get请求)
页面输入两个整数,通过AJAX传输到后端计算出结果并返回。
修改urls.py,增加cal路径
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
path('books/', views.books),
path('cal/', views.cal),
]
修改views.py,增加cal视图函数
def cal(request):
a = request.GET.get("a") #获取第一个值,类型为字符串
b = request.GET.get("b") #获取第二个值
res = int(a) + int(b) # 必须要转换为数字才能计算
return HttpResponse(str(res)) # HttpResponse只能接收字符串
修改index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<style type="text/css">
input {
width: 50px;
}
</style>
</head>
<body>
<input type="text" id="n1"> + <input type="text" id="n2"> =
<input type="text" id="result">
<button id="cal">计算</button>
<script>
$("#cal").click(function () {
var n1 = $("#n1").val();
var n2 = $("#n2").val();
//发送ajax请求
$.ajax({
url: "/cal/", //请求的url
type: "get", //默认get
data: {
a: n1,
b: n2
},
success: function (data) { //data接收响应体,必须要有
console.log(data); //打印响应体数据
$("#result").val(data); //修改p标签的text值
}
})
})
</script>
</body>
</html>
访问url:http://127.0.0.1:8000/index/
效果如下:
模拟停顿
先点击click,在输出数字进行计算。等待5秒后,出现书籍!
编辑views.py,导入time模块,修改books视图函数
from django.shortcuts import render,HttpResponse
import time
# Create your views here.
def index(request):
return render(request,"index.html")
def books(request):
time.sleep(5)
return HttpResponse("群山淡景")
def cal(request):
a = request.GET.get("a") #获取第一个值,类型为字符串
b = request.GET.get("b") #获取第二个值
res = int(a) + int(b) # 必须要转换为数字才能计算
return HttpResponse(str(res)) # HttpResponse只能接收字符串
修改index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<style type="text/css">
input {
width: 50px;
}
</style>
</head>
<body>
<button id="btn">click</button>
<p class="con"></p>
<hr>
<input type="text" id="n1"> + <input type="text" id="n2"> =
<input type="text" id="result">
<button id="cal">计算</button>
<script>
$("#btn").click(function () {
//发送ajax请求
$.ajax({
url:"/books/", //请求的url
type:"get", //默认get
success:function (data) { //data接收响应体,必须要有
console.log(data); //打印响应体数据
$(".con").text(data); //修改p标签的text值
}
})
});
$("#cal").click(function () {
var n1 = $("#n1").val();
var n2 = $("#n2").val();
//发送ajax请求
$.ajax({
url: "/cal/", //请求的url
type: "get", //默认get
data: {
a: n1,
b: n2
},
success: function (data) { //data接收响应体,必须要有
console.log(data); //打印响应体数据
$("#result").val(data); //修改p标签的text值
}
})
});
</script>
</body>
</html>
刷新页面,先点击click,在输入数值,最后点击计算。
效果如下:等待5秒,出现书籍
ajax加法运算(post请求)
更改cal视图函数,改为post接收数据
def cal(request):
a = request.POST.get("a") #获取第一个值,类型为字符串
b = request.POST.get("b") #获取第二个值
res = int(a) + int(b) # 必须要转换为数字才能计算
return HttpResponse(str(res)) # HttpResponse只能接收字符串
更改index.html,ajax改为post请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<style type="text/css">
input {
width: 50px;
}
</style>
</head>
<body>
<input type="text" id="n1"> + <input type="text" id="n2"> =
<input type="text" id="result">
<button id="cal">计算</button>
<script>
$("#cal").click(function () {
var n1 = $("#n1").val();
var n2 = $("#n2").val();
//发送ajax请求
$.ajax({
url: "/cal/", //请求的url
type: "post", //默认get
data: {
a: n1,
b: n2
},
success: function (data) { //data接收响应体,必须要有
console.log(data); //打印响应体数据
$("#result").val(data); //修改p标签的text值
}
})
});
</script>
</body>
</html>
刷新页面,重新计算。发现没有反应,打开浏览器控制台—>network
查看响应页面,这个页面看着熟悉吧。被django的csrf模块拦截了!
那么如何解决这个问题呢?
直接修改settings.py,注释掉csrf模块
post提交时,带上键值为csrfmiddlewaretoken的数据
第一种方案,显然不是我们想要的。我们选择第二种方案!
修改index.html,增加
{% csrf_token %}
完整代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<style type="text/css">
input {
width: 50px;
}
</style>
</head>
<body>
<input type="text" id="n1"> + <input type="text" id="n2"> =
<input type="text" id="result">
<button id="cal">计算</button>
{% csrf_token %}
<script>
$("#cal").click(function () {
var n1 = $("#n1").val();
var n2 = $("#n2").val();
//发送ajax请求
$.ajax({
url: "/cal/", //请求的url
type: "post", //默认get
data: {
a: n1,
b: n2
},
success: function (data) { //data接收响应体,必须要有
console.log(data); //打印响应体数据
$("#result").val(data); //修改p标签的text值
}
})
});
</script>
</body>
</html>
刷新页面,使用浏览器控制台,查看html代码
发现有一个input标签,name名为csrfmiddlewaretoken。后面有一个value值,这个是django生成的。每次刷新页面,它会变动!
我们不可能像爬虫一样,把这个value给爬下来!终极办法就是通过dom来获取input的值
通过属性选择器,可以精确的查找出input的值
$("[name=csrfmiddlewaretoken]")[0]
使用console来模拟dom操作
获取value值,使用val()
注意:在html标签里面, 只有input,select,textarea 这3个标签是用val拿值
修改index.html,增加参数csrfmiddlewaretoken
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<style type="text/css">
input {
width: 50px;
}
</style>
</head>
<body>
<input type="text" id="n1"> + <input type="text" id="n2"> =
<input type="text" id="result">
<button id="cal">计算</button>
{% csrf_token %}
<script>
$("#cal").click(function () {
var n1 = $("#n1").val();
var n2 = $("#n2").val();
var csrf = $("[name=csrfmiddlewaretoken]").val();
//发送ajax请求
$.ajax({
url: "/cal/", //请求的url
type: "post", //默认get
data: {
a: n1,
b: n2,
csrfmiddlewaretoken:csrf,
},
success: function (data) { //data接收响应体,必须要有
console.log(data); //打印响应体数据
$("#result").val(data); //修改p标签的text值
}
})
});
</script>
</body>
</html>
刷新页面,再次计算,就可以正常使用了!
基于Ajax进行登录验证
一般情况下,通常会将表单之类的标签放到form标签里面。这里我们使用form,只是把它当成一个容器而已!不使用submit按钮提交,而是使用ajax提交!使用div容器也是可以的!
注意点:
- 不写action,默认用当前的url
2.botton标签放到form标签之后,它具有sumbit功能**!**它和submit效果是一样的,会刷新页面!
那么需要使用按钮怎么办?在input里面,有一个type=”button”的。它有按钮效果,点击之后,没有任何反应!它在form表单里面,是安全的!没有默认事件!
那么它和ajax结合,就能实现某些功能。比如发送ajax请求!
修改index.html
注意:只要页面里面有下面的代码就可以,无论放到哪个位置都可以!只要jquery能获取到就行!
每次post提交,必须发送key为csrfmiddlewaretoken的值,否则提示403
这个是django给你发的身份证,如果没有身份证,那么django就会拦截
{% csrf_token %}
准备工作:准备一张表user
修改models.py,增加user表模型
from django.db import models
# Create your models here.
class User(models.Model):
user=models.CharField(max_length=32)
pwd=models.CharField(max_length=32)
使用下面2个命令生成表
python manage.py makemigrations
python manage.py migrate
插入2条数据,注意修改表名
INSERT INTO app01_user (id, user, pwd) VALUES (1, 'xiao', 123);
INSERT INTO app01_user (id, user, pwd) VALUES (2, 'zhang', 123);
修改urls.py,增加login路径
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
path('books/', views.books),
path('cal/', views.cal),
path('login/', views.login),
]
HttpResponse必须是一个字符串,因此想要返回一个字典,必须使用json序列化才行
修改views.py,增加login,完整代码如下:
from django.shortcuts import render,HttpResponse
from app01.models import User
import time
import json
# Create your views here.
def index(request):
return render(request,"index.html")
def books(request):
time.sleep(5)
return HttpResponse("群山淡景")
def cal(request):
a = request.POST.get("a") #获取第一个值,类型为字符串
b = request.POST.get("b") #获取第二个值
res = int(a) + int(b) # 必须要转换为数字才能计算
return HttpResponse(str(res)) # HttpResponse只能接收字符串
def login(request):
user = request.POST.get("user")
pwd = request.POST.get("pwd")
#根据表单的用户名和密码到数据库中匹配
user_obj = User.objects.filter(user=user, pwd=pwd).first()
#一般请求下,需要定义一个字典。msg是约定成俗的名字,用来做提示的
response = {"user":None,"msg":None}
if user_obj: # 判断有返回结果的请求下
response["user"] = user_obj.user # 修改字典的用户名
else:
response["msg"] = "用户名或者密码不一致" # 修改提示信息
#返回json格式数据,默认序列化时,对中文默认使用的ascii编码。
# ensure_ascii=False表示显示真正的中文
return HttpResponse(json.dumps(response, ensure_ascii=False))
修改index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<style type="text/css">
input {
width: 50px;
}
</style>
</head>
<body>
{% csrf_token %}
<h4>登录验证</h4>
<form>
<lable>用户名</lable><input type="text" id="user">
<lable>密码</lable><input type="password" id="pwd">
<input type="button" value="提交" id="login_btn">
{#显示错误信息#}
<span class="error"></span>
</form>
{% csrf_token %}
<script>
$("#login_btn").click(function () {
var csrf = $("[name=csrfmiddlewaretoken]").val();
//发送ajax请求
$.ajax({
url: "/login/", //请求的url
type: "post", //默认get
data: {
user: $("#user").val(),
pwd: $("#pwd").val(),
csrfmiddlewaretoken:csrf,
},
success: function (data) { //data接收响应体,必须要有
console.log(data); //打印响应体
console.log(typeof data); //打印数据类型
var data=JSON.parse(data); //反序列化数据
if(data.user){ // 登陆成功
//window.location.href表示跳转页面
alert("登录成功");window.location.href="/index/";
}
else{ // 登陆失败
//修改span标签,显示失败的返回值,并显示红色,左间距20px
$(".error").text(data.msg).css({"color":"red","margin-left":"20px"})
//设置定时器,2秒后清空提示信息
setTimeout(function () {
$(".error").text("") //清空提示信息
},2000)
}
}
})
});
</script>
</body>
</html>
注意:ajax里面的success接收的data响应体,必须要JSON.parse反序列才行
访问页面:http://127.0.0.1:8000/index/
效果如下:
ajax还有其他参数,可以设置,如下:
<button class="send_Ajax">send_Ajax</button>
<script>
$(".send_Ajax").click(function(){
$.ajax({
url:"/handle_Ajax/",
type:"POST",
data:{username:"Yuan",password:123},
success:function(data){
console.log(data)
},
error: function (jqXHR, textStatus, err) {
console.log(arguments);
},
complete: function (jqXHR, textStatus) {
console.log(textStatus);
},
statusCode: {
'403': function (jqXHR, textStatus, err) {
console.log(arguments);
},
'400': function (jqXHR, textStatus, err) {
console.log(arguments);
}
}
})
})
</script>
响应错误时,会执行error中的代码。
当 AJAX 请求正在进行时,执行complete的代码。
它可以做一个请求等待的效果!
二、文件上传
请求头ContentType
ContentType指的是请求体的编码类型,常见的类型共有3种:
1. application/x-www-form-urlencoded
这应该是最常见的 POST 提交数据的方式了。浏览器的原生