django 之 Ajax and so on

MTV与MVC(了解)??

MTV模型(django):??

M:模型层(models.py)
T:templates
V:views

MVC模型:??

M:模型层(models.py)
V:视图层(views.py)
C:控制器(Controller) urls.py

本质:?django的MTV也是MVC

多对多表三种创建方式

1.第一种 django orm自动帮我们创建??

models.py 模型表

 1 from django.db import models 2  3 Create your models here. 4 # 第一种创建方式: 5 class Book(models.Model): 6 name = models.CharField(max_length=32) 7 authors = models.ManyToManyField(to=Author) 多对多的关系,Book与Author之间的绑定 8  9 class Author(models.Model):10 name = models.CharField(max_length=32)

结论django orm 自动帮我们创建的第三张表是不可以对第三张表进行操作,如增加字段??

2.第二种纯手动创建第三张表??

models.py 模型表

from django.db import modelsCreate your models here.class Book(models.Model): name = models.CharField(max_length=32)class Author(models.Model): name = models.CharField(max_length=32)class Book2Author(models.Model): #foreignkey自动加_id book = models.ForeignKey(to=Book,on_delete=models.CASCADE) author = models.ForeignKey(to=Author,on_delete=models.CASCADE) #可以加字段,如果是jdango自动创建第三张表就不可以 info = models.CharField(max_length=32)

test.py 测试文件


 1 import os 2 import sys 3  4 if __name__ == __main__: 5 os.environ.setdefault(DJANGO_SETTINGS_MODULE, day60.settings) 6 import django 7  django.setup() 8 from app01 import models 9 10 # 查询书籍对应的作者11 # 正向12 res = models.Book.objects.filter(pk=1).values(author__name)13 print(res)14 # 报错信息(手动创建不支持orm方式取值)15 # django.core.exceptions.FieldError: Cannot resolve keyword ‘author‘ into field. Choices are: book2author, id, name16 # 反向17 book_obj = models.Book.objects.filter(pk=1).first()18 res= book_obj.author_set19 print(res)20 # 报错信息(不支持)21 # django.core.exceptions.FieldError: Cannot resolve keyword ‘author‘ into field. Choices are: book2author, id, name

View Code

结论纯手动创建多对多关系第三张表,可以增加字段,但是不符合ORM查询!!!????

3.第三种半自动创建第三张表??

models.py 模型表

 1 from django.db import models 2  3 Create your models here. 4  5 class Book(models.Model): 6 name = models.CharField(max_length=32) 7 #through=‘Book2Author‘ 告诉diango我自己创建了第三张表,你不用帮我创建了 8 #through_fields=((‘(字母小写)通过哪个参数可以查到我这张表‘,‘(字母小写)需要查询字段的表‘))  9 #虚拟字段,数据库看不到10 authors = models.ManyToManyField(to=Author,through=Book2Author,through_fields=(book,author))11 12 13 class Author(models.Model):14 name = models.CharField(max_length=32)15 # 也可以在这里关联16 # books = models.ManyToManyField(to=‘Book‘, through=‘Book2Author‘, through_fields=(‘author‘, ‘book‘))17 18 class Book2Author(models.Model):19 #foreignkey自动加_id20 book = models.ForeignKey(to=Book,on_delete=models.CASCADE)21 author = models.ForeignKey(to=Author,on_delete=models.CASCADE)22 #可以加字段,如果是jdango自动创建第三张表就不可以23 info = models.CharField(max_length=32)

test.py 测试文件


 1 import os 2 import sys 3  4 if __name__ == __main__: 5 os.environ.setdefault(DJANGO_SETTINGS_MODULE, day60.settings) 6 import django 7  django.setup() 8 from app01 import models 9 10 11 #正向查12 book = models.Book.objects.filter(pk=1).values(authors__name)13 print(book)14 book_obj = models.Book.objects.filter(pk=1).first()15 res1 = book_obj.authors.all()16 print(res1)17 #反向查询18 res = models.Author.objects.filter(pk=1).values(book__name)19 print(res)20 res2 = models.Author.objects.filter(pk=1).values(book2author__info)21 print(res2)22 23 24 # 结果:25 # < QuerySet[{‘authors__name‘: ‘yaya‘}] >26 # < QuerySet[ < Author: Author object(1) >] >27 # < QuerySet[{‘book__name‘: ‘书名‘}] >28 # < QuerySet[{‘book2author__info‘: ‘hahah‘}] >

View Code

结论:可扩展性高,可以增加字段,并且符合ORM查询方式 ???

前后端传输数据编码格式contentType

urlencoded??

index.html 前端文件

 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> 7  8 <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> 9 <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>10 11 <link href="https://cdn.bootcss.com/font-awesome/5.8.2/css/fontawesome.min.css" rel="stylesheet">12 <script src="https://cdn.bootcss.com/font-awesome/5.8.2/js/fontawesome.min.js"></script>13 14 <link href="https://cdn.bootcss.com/sweetalert/1.1.3/sweetalert.min.css" rel="stylesheet">15 <script src="https://cdn.bootcss.com/sweetalert/2.1.2/sweetalert.min.js"></script>16 </head>17 <body>18 <form action="" method="post" >19 <input type="text" name="name">20 <input type="text" name="password">21 22 <input type="submit">23 </form>24 </body>25 </html>

View Code

views.py 视图函数文件

from django.shortcuts import render,HttpResponse,redirectdef index(request): print(request.POST) return render(request,index.html,locals())

结论urlencoded  ??

  • 对应的数据格式:name=egon&password=123
  • 后端获取的数据:request.POST 
  • ps:django会将urlencoded编码的数据解析自动放到request.POST里

formdata

index.html 前端页面


 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> 7  8 <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> 9 <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>10 11 <link href="https://cdn.bootcss.com/font-awesome/5.8.2/css/fontawesome.min.css" rel="stylesheet">12 <script src="https://cdn.bootcss.com/font-awesome/5.8.2/js/fontawesome.min.js"></script>13 14 <link href="https://cdn.bootcss.com/sweetalert/1.1.3/sweetalert.min.css" rel="stylesheet">15 <script src="https://cdn.bootcss.com/sweetalert/2.1.2/sweetalert.min.js"></script>16 </head>17 <body>18 <form action="" method="post" >19 20 <input type="text" name="name">21 <input type="text" name="password">22 <input type="file" name="myfile">23 <input type="submit">24 </form>

View Code

views.py 视图函数文件

 1 from django.shortcuts import render,HttpResponse,redirect 2 import json 3 # Create your views here. 4 from app01 import models 5 from app01.utils import my_page 6 # form 表单支持urlencoded和formdata这两种方式 7 def index(request): 8 print(request.POST) 9 # <QueryDict: {‘name‘: [‘egon‘], ‘password‘: [‘123‘], ‘myfile‘: [‘1.png‘]}>10 # ‘myfile‘: [‘5.png‘]拿到的是文件的名字,并不是文件的内容11 print(request.FILES)12 # <MultiValueDict: {}> 为空13 return render(request,index.html,locals())

结论form 表单默认的是urlencoed, 不能获取到文件的对象,就是文件的内容,所以我们在form表单中要指定??

enctype="multipart/form-data"??????
后端中request.FILES中获取文件的对象
formdata
form表单传输文件的编码格式
后端获取文件格式数据:request.FILES
后端获取普通键值对数据:request.POST


首先先声明一下:????????
前端有哪些方式可以朝后端发请求:
浏览器窗口手动输入网址(get请求)
a标签的href属性(get请求)
form表单(get/post请求(默认是get请求))
ajax(get/post请求)

ajax

AJAX 不是新的编程语言,而是一种使用现有标准的新方法。

特点

1.局部刷新:AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。(这一特点给用户的感受是在不知不觉中完成请求和响应过程)如:github的注册,名字重新会提醒。

2.异步提交:客户发出一个请求之后,无需等待服务器响应结束,就可以发出第二个请求。

ajax基本语法

提交的地址(url)
提交的方式(type)
提交的数据(data)
回调函数(success)
<script>

$(‘#d1‘).click(function(){
$.ajax({
//提交的地址
url :‘/index‘,
//提交的方式
type:‘post‘,
//提交的数据
data:{‘name‘:‘jason‘,‘password‘:‘123‘},
//回调函数
success: function(data){ //data异步提交返回的结果
alert(data)
}
})

</script>
来个小例子趴??
页面输入两个整数,通过AJAX传输到后端计算出结果并返回。
views.py


 1 from django.shortcuts import render,HttpResponse,redirect 2 import json 3 Create your views here. 4 from app01 import models 5 from app01.utils import my_page 6  7 def index(request): 8 print(request.POST) 9 if request.method == POST:10 i1 = request.POST.get(i1)11 i2 = request.POST.get(i2)12 # res=i1+i2 字符串 13 res = int(i1)+int(i2) 要转成整型才可以进行运算14 print(res,type(res))15 return HttpResponse(res)16 return render(request, index.html, locals())

View Code

index.py 


 1 <input type="text" id="i1">+<input type="text" id="i2">=<input type="text" id="i3"> 2 <button id="d1">加我加我~</button> 3 <script> 4 $(#d1).click(function(){ 5  $.ajax({ 6 url:‘‘, //默认当前路径 7 type:post, //post小写就好 8 data:{i1:$(#i1).val(), i2:$(#i2).val()}, 9  success:function(data){10 $(#i3).val(data)11  }12  })13  })14 </script>

View Code

yaya对ajax的小理解:??????

前端的数据通过ajax方式提交给后端,然后会有一个返回的结果,前端并不需要等待结果,所以页面不刷新,可以继续输入,提交,页面都会显示你刚刚输入的数据(如果是form表单提交,提交页面会刷新,前端页面的数据就没有了),然后提交的数据结果是通过回调函数要回来进行展示的。

  • ajax传输json数据

index.html 


 1 <input type="text" id="i1">+<input type="text" id="i2">=<input type="text" id="i3"> 2 <button id="d1">加我加我~</button> 3 <script> 4 $(#d1).click(function(){ 5  $.ajax({ 6 url:‘‘, //默认当前路径 7 type:post, //post小写就好 8 contentType:application/json, 9 data :JSON.stringify({name:jason,hobby:study}),10  success:function(data){11 $(#i3).val(data)12  }13  })14  })15 16 </script>

View Code

views.py


 1 def index(request): 2  3 if request.method == POST: 4 print(request.POST) 5 print(request.body) #byte字符串 body除了用ajax方式提交数据才可以查看,其他方式查看会报错 6 data= request.body 7 #第一种方式 8 res = data.decode(utf-8) 9 #第二种方式10 # res2 = str(data,encoding=‘uyf-8‘)11 # print(res2,type(res2))12 res3 = json.loads(res)13 print(res3, type(res3))14 15 return HttpResponse(ok)16 return render(request, index.html, locals())

View Code

 

注意:?????

1.ajax提交的方式默认是urlencoed,如果前端在传输数据的时候没有说明是json格式传输数据的(没有写这句话contentType:‘application/json‘)就会以urlencoed的方式传输给后端,print(request.POST)  结果是?????? (以整个传输的字典数据当作是key,value是空)

 

2.ajax以json传输的数据不是在POST中(打印request.POST为空),而是在body里(打印request.body得到二进制数据??????),所以要进行解码

3.前后端传输数据,你不要骗人家,数据是什么格式就要告诉别人是什么格式,数据与编码一一对应??

4.body除了用ajax方式提交数据才查看,其他方式查看会报错

5.解码方式有两种:????

第一种方式res = data.decode(‘utf-8‘)

第二种方式res = str(data, encoding=‘utf-8‘)

  • ajax基于formdata传输文件:

index,html??


 1 <input type="file" name="myfile" id="i1"> 2 <button id="d1">加我加我~</button> 3  4 <script> 5 $(#d1).click(function() 点击id为d1的button按钮触发事件{ 6 //ajax需要借助对象FormData 7 let formdata = new FormData(); 8 //FormData 不仅可以传文件还可以传普通的键值对 9 formdata.append(name,jason);10 //如何获取input存放的文件11 $(#i1)[0] //jquery转原生js对象,js对象中有files的方法,然后从files[0]列表中取出文件对象12 formdata.append(myfile,$(#i1)[0].files[0]);13  $.ajax({14 url:‘‘, //默认当前路径15 type:post, //post小写就好16 contentType:formdata,//django能够自动识别该formdata对象,17 // 不要用任何编码,用我自带的formdata自带的编码格式18  data :formdata,19 //发送文件需要修改两个固定的参数20 processData:false, //告诉浏览器不要处理我的数据21 22  success:function(data){不要用任何的编码,就用我formdata自带的编码格式,django能够自动识别改formdata对象23 alert(收到了,老弟)24  }25  })26  })27 28 </script>

View Code

views.py

1 def index(request):2 if request.method == POST:3 print(request.POST)4 print(request.FILES)5 6 return HttpResponse(ok)7 return render(request, index.html, locals())

结论:??

$(‘button标签的id‘).click(function () {
let (FormData产生的对象变量名接收) = new FormData();
// FormData对象不仅仅可以传文件还可以传普通的键值对
(FormData产生的对象变量名).append(‘字典的key‘,‘字典的value‘);
// 获取input框存放的文件
//$(‘input的标签id‘)[0].files[0]
(FormData产生的对象变量名).append(‘自定义文件名‘,$(‘input的标签id‘)[0].files[0]);
$.ajax({
url:‘‘,
type:‘post‘,
data:formdata,
// ajax发送文件需要修改两个固定的参数
processData:false, // 告诉浏览器不要处理我的数据
contentType:false, // 不要用任何的编码,就用我formdata自带的编码格式,django能够自动识别改formdata对象
// 回调函数
success:function (后端返回的结果,变量名来接收) {
alert(后端返回的结果,变量名来接收)
}
})
});??

 

form表单与ajax异同点

1.form表单不支持异步提交局部刷新??
2.form表单不支持传输json格式数据??
3.form表单与ajax默认传输数据的编码格式都是urlencoded??

批量插入数据


 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> 7  8 <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> 9 <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>10 11 <link href="https://cdn.bootcss.com/font-awesome/5.8.2/css/fontawesome.min.css" rel="stylesheet">12 <script src="https://cdn.bootcss.com/font-awesome/5.8.2/js/fontawesome.min.js"></script>13 14 <link href="https://cdn.bootcss.com/sweetalert/1.1.3/sweetalert.min.css" rel="stylesheet">15 <script src="https://cdn.bootcss.com/sweetalert/2.1.2/sweetalert.min.js"></script>16 </head>17 <body>18 <div class="container">19 <div class="row">20 <div class="col-md-8 col-md-offset-2">21 <table class="table table-hover table-striped table-bordered">22 <thead>23 <tr>24 <th>id</th>25 <th>name</th>26 </tr>27 </thead>28 <tbody>29 {% for book_obj in book_list %}30 <tr>31 <td>{{ book_obj.pk }}</td>32 <td>{{ book_obj.name }}</td>33 </tr>34 </tbody>35 {% endfor %}36 </table>37 </div>38 </div>39 </div>40 </body>41 </html>

booklist.html

1 def booklist(request):2 #动态插入100条数据3 for i in range(100):4 models.Book2.objects.create(name=第%s本书 %i)5 # 查询所有的书籍展示到前端页面6 bool_list = models.Book2.objects.all()7 return render(request, booklist.html,locals())

views.py

以上是没有使用

models.表名.objects.bulk_create(列表) 没有使用所以网速刷新很慢

 1 def booklist(request): 2 #动态插入100000条数据 批量操作 3 l=[] 4 for i in range(10000): 5 l.append(models.Book2(name=第%s本书 %i)) 6 #批量操作(插入的数据多并且速度快) 7  models.Book2.objects.bulk_create(l) 8 # 查询所有的书籍展示到前端页面 9 book_list = models.Book2.objects.all()10 return render(request, booklist.html,locals())

 

自定义分页器

思路:??

1.?? book_list = models.Book2.objects.all()[0:10]
all()获取到Book2表中所有的书籍,列表套对象。然后列表可以切片索引(顾头不顾尾),这里是将书籍从索引为0的书籍作为第一个取出一直到索引为10的书籍展示在一个页面上;
2.??每页展示10条数据
per_page_num = 10
当前页(current_page)起始位置(page_start)终止位置(page_end)
1010
21020
32030

page_start = (current_page-1)*per_page_num
page_end = current_page*per_page_num
book_list = models.Book2.objects.all()[page_start:page_end
不管第1,第2,第3还是切换其他的当前页都可以显示对应的书籍序列,以上就推出了代码实现的变动。
3.??获取到访问的当前页crrent_page=request.get(‘page‘,1) 用户不传默认展示第一页
current_page=int(current_page) 得到的是字符串,所以要转成整型,才成进行运算
在前端需要访问url的时候还需要携带手动的输入当前页(不合理)
4.??然后再引用bootstrap的分页器,再为一个页面的a标签加上携带curent_page的参数,在用户点击的时候可以跳转相应的页面,但是缺陷是我这个页面只能显示固定的当前页数
5.??如果是100条数据,一页显示10条,需要显示10页,如果是101条,需要显示11页,用代码如何实现呢?
所以就用到了divmod

获取到数据的总条数:all_count = models.Book2.objects.all().count()
获取到总页数:pager_nums,more=divmod(all_count,per_page_num)
6.??页码的渲染通常是单数1,3,5,7,9符合中国人的审美标准

7.??由于需要循环拿出每一个当前页,但是前端没有range方法,所以只能到后端实现了之后再传给前端
 pager_nums,more = divmod(all_count,per_page_num)
if more:
pager_nums += 1

html = ‘‘
for i in range(1,pager_nums+1):
html += ‘<li><a href="?page=%s">%s</a></li>‘%(i,i)
8.??前端需要写{{page_obj.page_html|safe}} #safe将后端传入的html语法数据进行展示

自定义分页器的使用

1 from django.db import models??2 3 Create your models here.4 5 class Book2(models.Model):6 name = models.CharField(max_length=32)

在app01下自创的utils文件夹,导入第三方文件


 1 class Pagination(object): 2 def __init__(self, current_page, all_count, per_page_num=2, pager_count=11): 3 """ 4  封装分页相关数据 5  :param current_page: 当前页 6  :param all_count: 数据库中的数据总条数 7  :param per_page_num: 每页显示的数据条数 8  :param pager_count: 最多显示的页码个数 9  10  用法: 11  queryset = model.objects.all() 12  page_obj = Pagination(current_page,all_count) 13  page_data = queryset[page_obj.start:page_obj.end] 14  获取数据用page_data而不再使用原始的queryset 15  获取前端分页样式用page_obj.page_html 16 """ 17 try: 18 current_page = int(current_page) 19 except Exception as e: 20 current_page = 1 21  22 if current_page < 1: 23 current_page = 1 24  25 self.current_page = current_page 26  27 self.all_count = all_count 28 self.per_page_num = per_page_num 29  30 # 总页码 31 all_pager, tmp = divmod(all_count, per_page_num) 32 if tmp: 33 all_pager += 1 34 self.all_pager = all_pager 35  36 self.pager_count = pager_count 37 self.pager_count_half = int((pager_count - 1) / 2) 38  39  @property 40 def start(self): 41 return (self.current_page - 1) * self.per_page_num 42  43  @property 44 def end(self): 45 return self.current_page * self.per_page_num 46  47 def page_html(self): 48 # 如果总页码 < 11个: 49 if self.all_pager <= self.pager_count: 50 pager_start = 1 51 pager_end = self.all_pager + 1 52 # 总页码 > 11 53 else: 54 # 当前页如果<=页面上最多显示11/2个页码 55 if self.current_page <= self.pager_count_half: 56 pager_start = 1 57 pager_end = self.pager_count + 1 58  59 # 当前页大于5 60 else: 61 # 页码翻到最后 62 if (self.current_page + self.pager_count_half) > self.all_pager: 63 pager_end = self.all_pager + 1 64 pager_start = self.all_pager - self.pager_count + 1 65 else: 66 pager_start = self.current_page - self.pager_count_half 67 pager_end = self.current_page + self.pager_count_half + 1 68  69 page_html_list = [] 70 # 添加前面的nav和ul标签 71 page_html_list.append(‘‘‘ 72  <nav aria-label=‘Page navigation>‘ 73  <ul class=‘pagination‘> 74 ‘‘‘) 75 first_page = <li><a href="?page=%s">首页</a></li> % (1) 76  page_html_list.append(first_page) 77  78 if self.current_page <= 1: 79 prev_page = <li class="disabled"><a href="#">上一页</a></li> 80 else: 81 prev_page = <li><a href="?page=%s">上一页</a></li> % (self.current_page - 1,) 82  83  page_html_list.append(prev_page) 84  85 for i in range(pager_start, pager_end): 86 if i == self.current_page: 87 temp = <li class="active"><a href="?page=%s">%s</a></li> % (i, i,) 88 else: 89 temp = <li><a href="?page=%s">%s</a></li> % (i, i,) 90  page_html_list.append(temp) 91  92 if self.current_page >= self.all_pager: 93 next_page = <li class="disabled"><a href="#">下一页</a></li> 94 else: 95 next_page = <li><a href="?page=%s">下一页</a></li> % (self.current_page + 1,) 96  page_html_list.append(next_page) 97  98 last_page = <li><a href="?page=%s">尾页</a></li> % (self.all_pager,) 99  page_html_list.append(last_page)100 # 尾部添加标签101 page_html_list.append(‘‘‘102  </nav>103  </ul>104 ‘‘‘)105 return ‘‘.join(page_html_list)

my_page.py

 1 from django.shortcuts import render,HttpResponse 2 from app01 import models 3 from app01.utils import my_page 4  5 def booklist(request): 6 book_list = models.Book2.objects.all() 7 all_count = book_list.count() 8 current_page = request.GET.get(page,1) 9 page_obj = my_page.Pagination(current_page=current_page,all_count=all_count)10 page_queryset = book_list[page_obj.start:page_obj.end]11 return render(request,booklist.html,locals())

View Code

小总结:??

自定义分页器
页码的渲染通常都是单数1,3,5,7,9,符号中国人的审美标准


需要完善的
1.加首页和尾页
2.页码的个数应该是固定的


自定义分页器的使用
后端:
book_list = models.Book2.objects.all()
# 数据总条数
all_count = book_list.count()
# 当前页
current_page = request.GET.get(‘page‘,1)
# 示例一个分页器对象
page_obj = my_page.Pagination(current_page=current_page,all_count=all_count)
# 对总数据进行切片
page_queryset = book_list[page_obj.start:page_obj.end]

前端:
{{ page_obj.page_html|safe }} # 帮你渲染的是带有bootstrap样式的分页器

相关文章