Django之MTV与MVC、多对多表的创建方式、ajax、批量插入数据、自定义分页器

一、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模型。

二、多对多表的三种创建方式

第一种:

django自动帮我们创建

class Book(models.Model):
	name = models.CharField(max_length=32)
    # ManyToMany会自动帮我们创建第三张关联的表
	authors = models.ManyToManyField(to='Author')

class Author(models.Model):
	name = models.CharField(max_length=32)

第二种:

纯手动创建第三张表,这样创建的表,django的ORM的正向反向查询会不支持

class Book(models.Model):
	name = models.CharField(max_length=32)

class Author(models.Model):
	name = models.CharField(max_length=32)

class Book2Author(models.Model):
	book = models.ForeignKey(to='Book')
	author = models.ForeignKey(to='Author')
	info = models.CharField(max_length=32)

第三种(推荐使用)

半自动创建第三张表,这种方式可扩展性高,并且能符合ORM查询的规范。

我除了插入它们之间的关系外,还能插入一些其他的字段。这种方式也是以后用的最多的。

class Book(models.Model):
    name = models.CharField(max_length=32)
    authors = models.ManyToManyField(to='Author', through='Book2Author', through_fields=('book','author')))


class Author(models.Model):
    name = models.CharField(max_length=32)
    # 也可以把外键建在这张表
    # book = models.ManyToManyField(to='Book', through='Book2Author', through_fields=('author','book'))


class Book2Author(models.Model):
    book = models.ForeignKey(to='Book')  # django在创建时会自动在后面加_id
    author = models.ForeignKey(to='Author')  # django在创建时会自动在后面加_id
	info = models.CharField(max_length=32)

举例:支持对象与字段查询,支持正向与反向查询

from app01 import models
# 查询书籍对应的作者
res = models.Book.objects.filter(pk=1).values('authors__name')
print(res)
book_obj = models.Book.objects.filter(pk=1).first()
print(book_obj.authors.all())
# 查询作者对应的书籍
res = models.Author.objects.filter(pk=1).values('book__name')
print(res)
# 查询书籍对应的信息
res = models.Book.objects.filter(pk=1).values('book2author__info')
print(res)
res = models.Book.objects.filter(pk=1).values('book2author__author__name')
print(res)

 Django之MTV与MVC、多对多表的创建方式、ajax、批量插入数据、自定义分页器_第1张图片

三、Ajax

在开始学习ajax之前,先来看一下前后端传输数据的编码格式:contentType

urlencoded:默认的类型(enctype="application/x-www-form-urlencoded"),不支持文件传输。form表单

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

formdata:指定编码,支持文件传输(enctype="multipart/form-data")。form表单

  • form表单传输文件的编码格式
  • 后端获取文件格式数据:request.FILES
  • 后端获取普通键值对数据:request.POST

application/json:这个不是form表单里指定的,而是在ajax内指定使用json格式传递字符串

  • ajax发送json格式的数据要用的编码
  • 编码与数据格式要一致

可以往后端发送请求的方式有:

  1.  浏览器窗口手动输入网址:get请求
  2. a标签的href属性:get请求
  3. form表单:get/post请求(默认是get请求)
  4. ajax:get/post请求

ajax的特点:

  • 异步提交:即提交任务后可以继续提交其他任务,而不用在原地等待结果
  • 局部刷新:即只在浏览器页面用到数据的位置刷新,不会刷新整个页面 

 ajax的基本语法:

  1. 提交的地址(url)
  2. 提交的方式(type)
  3. 提交的数据(data)
  4. 回调函数(success)
//给id为d1的按钮绑定点击事件,向后端发送数据,然后通过回调函数拿到后端处理的结果
$('#d1').click(function () {
    $.ajax({
        //提交的地址,可以不写,默认发到当前页面打开的地址
        url:'/index/,
        //提交的方式
        type:'post',
        //提交的数据
        data:{'name':'shj', 'password':'123'},
        //回调函数
        success:function (data) {    //data接收到的就是异步提交返回的结果
            alert(data)
        }
    })

})

 ajax默认传输数据的编码格式也是urlencoded。

前后端在传输数据时,数据与编码格式要一一对应,你传的是json格式就不要忘了指定编码。

往后端传数据举例: 

Django之MTV与MVC、多对多表的创建方式、ajax、批量插入数据、自定义分页器_第2张图片 

只要是post请求,一定要去配置文件中注销这一段:

Django之MTV与MVC、多对多表的创建方式、ajax、批量插入数据、自定义分页器_第3张图片 

小练习:

 在前端页面展示三个input框,然后将前两个框的和通过ajax异步提交渲染到第三个框。

+=

def index(request):
    if request.method == 'POST':
        i1 = request.POST.get('i1')
        i2 = request.POST.get('i2')
        i3 = int(i1) + int(i2)
        print(i3, type(i3))
        return HttpResponse(i3)
    return render(request, 'index.html')

 

 ajax传输json类型的数据

前端:

$('#d1').on('click', function () {
    $.ajax({
        url:'',  //可以不写,默认就是当前打开的页面
        type:'post',
        contentType:'application/json',
        data:JSON.stringify({'name':'shj','hobby':'study'}),
        success:function (data) {
            //可以为空
        }
    })
});

后端:request.body只有传递json格式的数据时才有用,能被打印查看

def index(request):
    if request.method == 'POST':
        import json
        data = request.body
        print(data)  # b'{"name":"shj","hobby":"study"}'
        res = data.decode('utf-8')
        print(res, type(res))  # {"name":"shj","hobby":"study"} 
        dic = json.loads(res)
        print(dic, type(dic))  # {'name': 'shj', 'hobby': 'study'} 
        return HttpResponse('OK')
    return render(request, 'index.html')

ajax传输文件:

借助内置对象FormData可以传输文件,也可以传输普通的键值对。格式如下:

formdata.append('键', '值')

 前端:

$('#d1').click(function () {
   let formdata = new FormData();
   // FormData对象不仅仅可以传文件还可以传普通的键值对
	formdata.append('name','jason');
	// 获取input框存放的文件
	//$('#i1')[0].files[0]
	formdata.append('myfile',$('#i1')[0].files[0]);
	$.ajax({
		url:'',
		type:'post',
		data:formdata,
		// ajax发送文件需要修改两个固定的参数
		processData:false,  // 告诉浏览器不要处理我的数据
		contentType:false,  // 不要用任何的编码,就用formdata自带的编码格式,django能够自动识别该formdata对象
		// 回调函数
		success:function (data) {
			alert(data)
		}
	})
});

后端:文件解析后放在request.FILES,普通的键值对解析后放在request.POST中

def index(request):
    if request.method == 'POST':    
        file_obj = request.FILES.get('myfile')
        print(file_obj.name)
        with open(file_obj.name,'wb') as f:
            for line in file_obj.chunks():  # 这里.chunks()可加可不加,反正for循环也是一行一读
                f.write(line)
        return HttpResponse('上传成功')
    return render(request, 'index.html')

form表单与ajax的异同点

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

四、批量插入数据 

先建一张表:

class Book2(models.Model):
    name = models.CharField(max_length=32)

如果我要100条数据:

def book_list(request):
    for i in range(100):
        models.Book2.objects.create(name='第%s本书'%i) 
    return render(request,'booklist.html',locals())

上面插入100条数据的时候,明显感觉到速度很慢。如果插入10000条呢,现在就要用到一个批量插入。

def book_list(request):
    l = []
    for i in range(10000):
        l.append(models.Book2(name='第%s本书' % i))  # 实例化出一些对象
    models.Book2.objects.bulk_create(l)
    

五、自定义分页器

补充一点:前端需要根据当前页面展示第几页。

  • 1
  •    # 直接写?page=1会自动补全当前路径。

    自定义分页器的使用:

    后端:

    from django.shortcuts import render,HttpResponse
    from app01 import models
    from app01.utils import my_page
    
    def booklist(request):
        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]  # 切片,每页展示多少条
        return render(request,'booklist.html',locals())

    前端:渲染的是带有bootstrap样式的分页器

    Django之MTV与MVC、多对多表的创建方式、ajax、批量插入数据、自定义分页器_第4张图片

    在应用app01下新建一个utils文件夹,在下面新建 my_page.py文件

    class Pagination(object):
        def __init__(self, current_page, all_count, per_page_num=2, pager_count=11):
            """
            封装分页相关数据
            :param current_page: 当前页
            :param all_count:    数据库中的数据总条数
            :param per_page_num: 每页显示的数据条数
            :param pager_count:  最多显示的页码个数
    
            用法:
            queryset = model.objects.all()
            page_obj = Pagination(current_page,all_count)
            page_data = queryset[page_obj.start:page_obj.end]
            获取数据用page_data而不再使用原始的queryset
            获取前端分页样式用page_obj.page_html
            """
            try:
                current_page = int(current_page)
            except Exception as e:
                current_page = 1
    
            if current_page < 1:
                current_page = 1
    
            self.current_page = current_page
    
            self.all_count = all_count
            self.per_page_num = per_page_num
    
            # 总页码
            all_pager, tmp = divmod(all_count, per_page_num)
            if tmp:
                all_pager += 1
            self.all_pager = all_pager
    
            self.pager_count = pager_count
            self.pager_count_half = int((pager_count - 1) / 2)
    
        @property
        def start(self):
            return (self.current_page - 1) * self.per_page_num
    
        @property
        def end(self):
            return self.current_page * self.per_page_num
    
        def page_html(self):
            # 如果总页码 < 11个:
            if self.all_pager <= self.pager_count:
                pager_start = 1
                pager_end = self.all_pager + 1
            # 总页码  > 11
            else:
                # 当前页如果<=页面上最多显示11/2个页码
                if self.current_page <= self.pager_count_half:
                    pager_start = 1
                    pager_end = self.pager_count + 1
    
                # 当前页大于5
                else:
                    # 页码翻到最后
                    if (self.current_page + self.pager_count_half) > self.all_pager:
                        pager_end = self.all_pager + 1
                        pager_start = self.all_pager - self.pager_count + 1
                    else:
                        pager_start = self.current_page - self.pager_count_half
                        pager_end = self.current_page + self.pager_count_half + 1
    
            page_html_list = []
            # 添加前面的nav和ul标签
            page_html_list.append('''
                        
                                               
                                           ''')
            return ''.join(page_html_list)

     

    你可能感兴趣的:(Django框架)