Django框架-模型层3/数据传输/Ajax 一、orm查询优化 二、模型层choices参数 三、MTV与MVC模型 四、Ajax简介 五、前后端传输数据编码格式 六、序列化(drf会用到)

能少走数据库就少走数据库。

1.only与defer

only:取对象,对象中只包含主键和only括号里的属性。

only括号内放字段,查询结果是一个列表套一个个的数据对象。

这些数据对象通过点的方式取括号内的字段属性不会再查询数据库,直接就是对象获取属性。只需要查一次数据库就可以全取出。

不过only也可以点击括号内没有的字段,但是每点击一次就会重新走一次数据库查询,效率极低。

res = models.Book.objects.only('title')
for i in res:
    print(i.title)  # 走一次

for i in res:
	print(i.price)  # 走11次,有几个对象走几次

defer:与only相反,排除括号内的字段。

defer与only是互为反操作。

defer括号内放什么字段,查询出来的对象就没有该字段属性。

如果你要点击括号内的对象,每点击一次就要重新走一次数据。

而你如果点击了非括号内的字段,就不会走数据库,仅仅是对象点属性取值的操作。

res = models.Book.objects.defer('title')
# print(res)
for i in res:
    print(i.title)  # 有几个对象走几次

for i in res:
    print(i.price)  # 走一次

2.select_related与prefatch_related

select_related:用来优化查询外键的操作。

select_related括号内只能放外键字段,并且外键字段的类型只能是一对多 或者一对一,不能是多对多。多对多会报错。

内部是join自动连表操作,会将括号内外键字段所关联的表与当前表自动拼接成一张表。

然后将表中的数据一个个查询出来封装成一个个的对象。

这样做的好处就在于跨表也不需要重复的走数据库了,减轻数据库的压力 。

select_related括号内可以放多个外键字段(不能是多对多),逗号隔开,会将多个外键字段关联的表与当前表通过sql语句的join方法全部拼成一张大表。

耗时:数据库层面需要先连表,耗时耗在连表需要的时间。

res = models.Book.objects.select_related('publisher')
for i in res:
    print(i.title) 
    print(i.publisher)

prefatch_related:prefetch_related内部是子查询。

会自动帮你按步骤查询多张表 ,然后将查询的结果封装到对象中。

给用户的感觉好像还是连表操作。实际内部方法不一样。

括号内支持传多个外键字段,并且没有类型限制。

特点:每放一个外键字段,就会多走一条sql语句,多查询一张表。

耗时:查询的次数长,耗时耗在查询次数上。

res = models.Book.objects.prefetch_related('publisher','authors')
for i in res:
    print(i.title)
    print(i.publisher)

两者之间的优缺点:

需要结合实际情况,看表的大小。

在两张表都特别大的情况下,连表操作可能耗时更多。

二、模型层choices参数

choices参数是模型层中字段的参数,choices属性的值需要为一个提前定义的对应关系容器。

容器内写数字integerfield(也可以是字符charfield)与状态的对应关系,以元组的形式存在一个大元组里。

# models
class User(models.Model):
    sex_choices = (
        (1,'男'),
        (2,'女'),
        (3,'不愿透露'),
    )
    sex = models.IntegerField(choices=sex_choices)
    # 该字段存数字
    # 可以存提前定义好的关系中的数字,也可以存不在关系中的数字
    # 但是取得时候,也可以正常取,但取的是数字
    
# test
# 字段中存choices字段类型时,如果想要取出数字对应的值需要用‘get_字段名_display()’方法来获取
user_obj = models.User.objects.get(pk=1)
user_obj1 = models.User.objects.get(pk=4)
# print(user_obj.gender)
# print(user_obj1.gender)  # 可以正常取,但,是数字
# print(user_obj.get_gender_display())
print(user_obj1.get_gender_display())  # 没有对应关系,获取到的还是数字本身

三、MTV与MVC模型

1.MVC

MVC(Model View Controller 模型-视图-控制器)

是一种Web架构的模式。特点:把业务逻辑、模型数据、用户界面分离开来,让开发者将数据与表现解耦。

Model: 代表数据存取层,

View: 代表的是系统中选择显示什么和怎么显示的部分,

Controller: 指的是系统中根据用户输入并视需要访问模型,以决定使用哪个视图的那部分。

2.MTV

Django框架就是MTV结构的。其实本质还是MVC。

MTV(Model Templates View 模型-模板-视图):

1.Models:数据存取层。

该层处理与数据相关的所有事务: 如何存取、如何验证有效,是一个抽象层,用来构建和操作你的web应用中的数据,模型是你的数据的唯一的、权威的信息源。它包含你所储存数据的必要字段和行为。通常,每个模型对应数据库中唯一的一张表。

2.模板(templates):即表现层。

该层处理与表现相关的决定: 如何在页面或其他类型文档中进行显示。模板层提供了设计友好的语法来展示信息给用户。使用模板方法可以动态地生成HTML。模板包含所需HTML 输出的静态部分,以及一些特殊的语法,描述如何将动态内容插入。

3.视图(views):业务逻辑层。

该层包含存取模型及调取恰当模板的相关逻辑。用于封装负责处理用户请求及返回响应的逻辑。视图可以看作是前端与数据库的中间人,他会将前端想要的数据从数据库中读出来给前端。他也会将用户要想保存的数据写到数据库。

3.区别

MVC中的View的目的是「呈现哪一个数据」,而MTV的View的目的是「数据如何呈现」。

也就是把MVC中的View分成了视图(展现哪些数据)和模板(如何展现)2个部分,而Contorller这个要素由框架自己来实现了,我们需要做的就是把(带正则表达式的)URL对应到视图就可以了,通过这样的URL配置,系统将一个请求发送到一个合适的视图。

四、Ajax简介

AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(XML也是一门标记语言,当然,传输的数据不只是XML)。

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

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

AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。

  • 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
  • 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。

在前端页面中,Ajax句式非常简单,用jQuery可以很方便的实现:

// 使用jQuery之前先导入jQuery
// ajax基本语法结构
$.ajax({
	url:'', // 数据提交的后端地址,不写就是往当前页面提交,也可以写后缀,也可以写全称,跟actions一样
	type:'post',  // 提交方式,不写默认是get请求
	data:"{i1:$('#d1'),i2:$('#d2')}",  // 提交的数据
	success:function(backdata){ // 形参backdata就是异步提交之后后端返回结果
		$('#d3').val(backdata)  // 这里是回调机制需要做的事情
	}
})

一旦使用了ajax,三板斧都不会再作用域页面,而是和回调函数做交互。

五、前后端传输数据编码格式

前后端交互时,不同数据的编码格式是不一样的。

比如说你用form表单提交数据的时候,传普通的input框的文本和file文件时,后端可以用request.POST/request.FILES 接收文本和文件。

那么后端为什么可以识别你传的是文本还是文件呢?

就是因为你传输不同数据时所使用的编码格式不一样。

1. 不同的编码格式

目前,我们需掌握的编码格式有三种:

  1. urlencoded (默认,文本)
  2. form-data (文件)
  3. application/json (json格式的数据)

2. 前端朝后端发送数据的请求方式

  1. a标签href参数:get请求
  2. form表单:get/post
  3. ajax:get/post

2.1 form表单发送数据编码格式

django后端只要你的数据满足urlencoded格式:username=tbw&password=123就会自动帮你解析到request.POST中。

如果你是一个文件对象django后端也会自动识别帮你放到request.FILES中。

form表单无法发送json格式的数据。

  1. 默认格式

    Content-Type: application/x-www-form-urlencoded(谷歌浏览器可以看)

    form表单发送数据默认编码格式为:urlencoded。

    此格式的形式为:username=tbw&password=123

    django后端针对urlencoded数据 会自动解析并且帮你封装到request.POST中。

  2. 文件

    Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryhjKCHQHDmcE62iMQ

    form表单发送文件数据的编码格式为:form-data

    此格式的形式:你在浏览器上是无法查看到

  3. json

    form表单无法发送json格式的数据。你只能借助于ajax。

2.2 ajax发送数据的编码格式

ajax能够发送:
1.urlencoded
2.form-data
3.application/json
三种格式的数据。

  1. 默认格式

    编码格式为:urlencoded。

    也就意味着后端django也是将数据解析到request.POST中。

  2. ajax发送文件

    编码格式为:form-data。

    需要借助于内置对象:new FormData()

    该对象既可以携带文件数据,也支持普通的键值对。

     $('#d1').click(function () {
         // 先生成一个内置对象
         var MyFormData = new FormData();
         // 1. 先添加普通的键值
         MyFormData.append('username','tbw');  // 添加了一组普通的键值对
         MyFormData.append('hobby',['read','run']);
         // 2. 添加文件数据
         MyFormData.append('myfile',$('#d2')[0].files[0]);  // 如何获取input框中文件对象$('#d1')[0].files[0]
         $.ajax({
             url:'',
             type:'post',
             data:MyFormData,
             // 发送文件必须要指定的两个参数
             contentType:false,  // 不适用任何编码  MyFormData对象内部自带编码 django后端能够识别
             processData:false,  // 不要处理数据
             success:function (data) {
             }
         })
     })
    
  3. ajax发送json格式数据

    ajax发送json格式数据的方式:

    $('#d1').click(function () {
    	$.ajax({
    		url:'',
    		type:'post',
    		contentType:'application/json',
    		data:JSON.stringify({'username':'jason','password':'123'}),
    		success:function (data) {
    		alert(123)
    	}
    })
    

    Django后端接收json格式数据的方法:

    # django后端针对json格式的数据不会做任何处理,
    # 数据怎么来的,只会原封不动的放到request.body中,也就是接收到的是二级制数据
    json_bytes = request.body
    # 解码
    # json_str = str(json_bytes,encoding='utf-8')
    json_str = json_bytes.decode('utf8')
    # 反序列化
    json_dic = json.loads(json_str)
    # json_dic = json.loads(json_bytes)  # 自动帮你解码加反序列化
    print(json_dic,type(json_dic))
    

六、序列化(drf会用到)

目的:将数据整合成一个大字典形式,方便数据的交互。

使用serializers模块完成序列化。

from django.core import serializers
def zzz(request):
	user_queryset = models.User.objects.all()
	res = serializers.serialize('json',user_queryset)
	return HttpResponse(res)