首页 > 其他分享 >框架第八课---Q查询进阶操作,ORM查询优化(重点!),ORM事务操作,ORM常用字段类型,ORM常用字段参数,ORM三种创建多对多的方式,Ajax请求(前端经常要用)

框架第八课---Q查询进阶操作,ORM查询优化(重点!),ORM事务操作,ORM常用字段类型,ORM常用字段参数,ORM三种创建多对多的方式,Ajax请求(前端经常要用)

时间:2022-12-19 22:22:40浏览次数:44  
标签:obj models res 查询 ORM 常用字 数据

上周内容回顾

  • 图书管理系统

    1.表的设计与创建
    	书籍表、出版社表、作者表、作者详情表
    2.开设图书管理系统首页接口
    	前端页面搭建
    3.开设图书列表展示页
    	ORM查询、过滤器、标签
    4.开设图书添加页
    	ORM操作
    5.开设图书编辑页
    	路由动态匹配、视图函数传参
    6.开设图书删除页
    	前端js二次确认
    
  • 聚合查询

    和数据库相关的,和models相关的,这些模块一般都在django.db或者django.db.models下面!!!
    from django.db import Max,Min,Sum,Avg,Count
    
    整张表默认是一组 直接使用聚合函数也可以
    models.Book.objects.aggregate(Max('price'),min_price=Min('price'))
    
  • 分组查询

    models.Book.objects.annotate()	按照整张表的主键值分组
    models.Book.objects.values('字段').annotate()	按照括号内指定的字段分组
    
  • F与Q查询

---------------------------------------------------

F 能够帮助我们,去获取表中另外字段所对应的数据!!
F:获取表中指定字段对应的数据作为查询条件!!!

from django.db.models import F
models.Book.objects.filter(kucun__gt=F('maichu'))  # 书表里面库存数大于买出数的书对象
models.Book.objects.update(price=F('price') + 888) # 每一条数据都是原来价格加了888

ps:针对字符串类型的数据拼接需要使用模块concat、values
---------------------------------------------------

Q:可以将多个查询条件的关系做修改!!!  用Q将条件包起来!!!
from django.db.models import Q

models.Book.objects.filter(Q(pk=1),Q(title='三国'))    # and关系
models.Book.objects.filter(Q(pk=1) | Q(title='三国'))  # or关系
models.Book.objects.filter(~Q(pk=1),Q(title='三国'))   # not关系

Q与Q之间用逗号连接and关系    Q与Q之间用管道符连接or关系
Q前面加波浪号代表该Q的条件取反!!!

今日内容概要

  • Q查询进阶操作!!!
  • ORM查询优化!!!面试可能会问
  • ORM事务操作
  • ORM常用字段类型
  • ORM常用字段参数
  • ORM三种创建多对多的方式
  • Ajax请求

今日内容详细

Q查询进阶操作

Q的另外一个作用是:能够将查询条件的左侧字段名变成字符串的形式!!!
将查询条件变为字符串,就具备了和用户互动的条件了!!!

from django.db.models import Q

q_obj = Q()      # 1. 产生q对象

q_obj.connector = 'or'      # 默认多个条件的连接是and,也手动可以修改为or
q_obj.children.append(('pk', 1))      # 2. 添加查询条件
q_obj.children.append(('price__gt', 2000))     # 3. 支持添加多个
res = models.Book.objects.filter(q_obj)     # 4. 查询支持直接填写q对象

print(res)
----------------------------------------------
q_obj = Q()
q_obj.connector = 'or'
q_obj.children.append(('pk', '1'))
q_obj.children.append(('title__contains', '三'))
res = models.Book.objects.filter(q_obj)

# 这个'三'  就可以有用户在前端输入,后端通过request动态获取!!!
# 查询 书籍表里面title字段里面数据有含有三的书籍对象!!!

.
.
.

ORM查询优化 重点!!!

优化主要就是优化的sql执行的次数,优化查询数据的时间!!

1.ORM的查询默认都是惰性查询!!!

-------------------------------------------
res = models.Book.objects.all()

print('hehe')

# 这种情况下如果ORM语句的下面的代码里,都没有引用到接收该sql语句的变量名时,这个时候django就默认不执行这句话了,这种现象就叫做惰性查询!!!
-------------------------------------------

.
.

2.ORM的查询自带分页处理!!!


所以将来自己写sql对一张表进行数据查询时,最好要在sql语句的最后加个limit限制一下查询数据的展示的数量!!!
ORM的查询自带分页处理!!!ORM会自动帮我分页,防止当表里面数据特别多的时候,一下子把电脑搞卡死了!!!所以将来自己写sql对一张表进行数据查询时,最好要在sql语句的最后加个limit限制一下查询展示的数量!!!

image
.
.

3.only与defer 关键字

面试甚至会出考题考你,对象点字段名,哪一个走了sql查询,哪一个没走sql查询!!!
-----------------------------

res = models.Book.objects.all()  # queryset [数据对象、数据对象]
for obj in res:
    print(obj.title)  # 点击括号内填写的字段 不走SQL查询
    print(obj.price)

这种情况下 只会走一条sql语句,查询所有数据,然后将所有数据封装到queryset对象里面去!!
后续的for循环出一个一个的数据对象,以及用数据对象点的方式拿对象里面的数据都不再走数据库的查询了!!!
-------------------------------------------
需求:只想要书名和价格

res = models.Book.objects.all().values('title','price')  # queryset [{},{},{}]
print(res)  # queryset [{'title':'三国演义','price': Decimal('22.2')},{},{}]

for i in res: # 此时i 是一个个的字典{'title':'三国演义','price':Decimal('22.2')}
    print(i.title)
    print(i.price)   # 此时字典是没办法通过点的方式取值的,所以会报错!

---------------------------------------------
上面all()得到的结果是一个一个的数据对象,但是每个数据对象里面含有的是所有的字段名!
上面values()方法得到的结果虽然是一个一个的字典,每个字典里面里面含有的是指定字段的数据!

.
.

关键字 only
感觉像是all的升级版 all拿到的对象里面什么字段都有,only拿到的对象里面只有括号里面指定的字段名,后续用对象点括号里面有的字段名不走sql查询,点没有的字段名会走sql查询

only方法的作用是:可以将括号里面所列举的字段封装到数据对象里面,当数据对象点击这些字段的时候是不会走sql查询的。
但是如果用数据对象去点击括号里面所没有填写的字段时,可以拿到数据,但是每点一次都会走一次sql数据库查询。

需求升级:只获取指定字段的数据,并且结果还是一个的数据对象!!!

res = models.Book.objects.only('title', 'price')

print(res)         # queryset [数据对象、数据对象]
for obj in res:
print(obj.title)
print(obj.price)     # 点击括号内填写的字段 不走SQL查询
# 这种情况下用only获取到的对象,可以直接点击它括号里面的字段,不会走sql语句

print(obj.publish_time)  # 也可以点击括号内没有的字段获取数据 但是会走SQL查询

-------------

.
.

关键字 defer 和only作用相反,拿到的对象里面不要括号里面指定的字段名,其他的字段名都要!!!后续用对象点括号里面有的字段名就会走sql查询,点没有的字段名就不走sql查询
res = models.Book.objects.defer('title', 'price')
print(res)  # queryset [数据对象、数据对象]
for obj in res:
print(obj.title)       # 点击括号内填写的字段 走SQL查询
print(obj.price)
print(obj.publish_time)      # 点击括号内没有的字段获取数据 不走SQL查询

.
.

面试问的频率可能更高!!!
select_related关键字

res = models.Book.objects.all()
for obj in res:
    print(obj.title)    #  不走SQL查询,all的sql查询将所有数据都塞到每个对象里面了

    print(obj.publish.name)    # 当用数据对象点关联的出版社表里面的数据时,每次查询都需要走SQL查询
------------------------------------------------
------------------------------------------------
res = models.Book.objects.select_related('publish')  # 括号内支持一对多外键字段
# 提前先连表后查询数据,最后封装到一个个对象里面去!
for obj in res:
    print(obj.publish.name)      # 不再走SQL查询!!!

# 先将书表和出版社表拼到一起,然后把大表里面的所有数据封装到一个个书籍对像里面去
# 这样拿到的对象通过点的方式既可以点书表里面的所有字段,也可以点出版社表里面的所有字段
# 所以就不许要再走sql查询了!!!
------------------------------------------------
------------------------------------------------
res = models.Book.objects.select_related('authors')  # 括号内不支持多对多外键字段
res1 = models.Author.objects.select_related('author_detail')  # 括号内一对一外键字段也支持
print(res1)
-------------------------------------------------

.

res = models.Book.objects.prefetch_related('publish')  # 子查询,总共执行两条sql语句
for obj in res:
    print(obj.publish.name)  # 不再走SQL查询!

# prefetch_related()  括号里面也是只能填写外键字段(除了多对多)
# 作用是 先把书表里面的所有数据查出来,然后基于书里面publish_id对应的值,再到出版式表里面,把对应的数据再查出来,之后封装起到一个个的书籍对象里面去

.
.

ORM事务操作

"""
1.事务的四大特性(ACID)
	原子性、一致性、隔离性、持久性
2.相关SQL关键字
	start transaction;
	rollback;
	commit;
	savepoint;
3.相关重要概念
	脏读、幻读、不可重复读、MVCC多版本控制...
"""
django orm提供了至少三种开启事务的方式
	方式1:配置文件数据库相关添加键值对		全局有效
       "ATOMIC_REQUESTS": True每次请求所涉及到的orm操作同属于一个事务
	方式2:装饰器							局部有效
       from django.db import transaction
       @transaction.atomic
       def index():pass	
 	方式3:with上下文管理					局部有效
       from django.db import transaction
    	def reg():
    		with transaction.atomic():
             pass

.
.
.
.

ORM常用字段类型

AutoField
	primary_key=True
CharField
	max_length
IntegerField
BigIntergerField
DecimalField
	max_digits decimal_places
DateField
	auto_now auto_now_add
DateTimeField
	auto_now auto_now_add
BooleanField
	传布尔值自动存0或1
TextField
	存储大段文本
EmailField
	存储邮箱格式数据
FileField
	传文件对象 自动保存到提前配置好的路径下并存储该路径信息
    
ORM还支持用户自定义字段类型
	class MyCharField(models.Field):
        def __init__(self, max_length, *args, **kwargs):
            self.max_length = max_length
            super().__init__(max_length=max_length, *args, **kwargs)

        def db_type(self, connection):
            return 'char(%s)' % self.max_length


    class User(models.Model):
        name = models.CharField(max_length=32)
        info = MyCharField(max_length=64)

.
.
.
.

ORM常用字段参数

primary_key 	主键
verbose_name	注释
max_length		字段长度
max_digits     小数总共多少位
decimal_places	小数点后面的位数
auto_now		每次操作数据自动更新事件
auto_now_add	首次创建自动更新事件后续不自动更新
null			允许字段为空
default			字段默认值
unique			唯一值
db_index		给字段添加索引
choices			当某个字段的可能性能够被列举完全的情况下使用
	性别、学历、工作状态、...
	class User(models.Model):
        name = models.CharField(max_length=32)
        info = MyCharField(max_length=64)
        # 提前列举好对应关系
        gender_choice = (
            (1, '男性'),
            (2, '女性'),
            (3, '其他'),
        )
        gender = models.IntegerField(choices=gender_choice,null=True)
    user_obj = User.objects.filter(pk=1).first()
    user_obj.gender 
    user_obj.get_gender_display()


to				关联表
to_field		关联字段(不写默认关联数据主键)
on_delete		当删除关联表中的数据时,当前表与其关联的行的行为。
	 1、models.CASCADE
        级联操作,当主表中被连接的一条数据删除时,从表中所有与之关联的数据同时被删除
    2、models.SET_NULL
        当主表中的一行数据删除时,从表中所有与之关联的数据的相关字段设置为null,此时注意定义外键时,这个字段必须可以允许为空
    3、models.PROTECT
        当主表中的一行数据删除时,由于从表中相关字段是受保护的外键,所以都不允许删除
    4、models.SET_DEFAULT
        当主表中的一行数据删除时,从表中所有相关的数据的关联字段设置为默认值,此时注意定义外键时,这个外键字段应该有一个默认值
    5、models.SET()
        当主表中的一条数据删除时,从表中所有的关联数据字段设置为SET()中设置的值,与models.SET_DEFAULT相似,只不过此时从表中的相关字段不需要设置default参数
    6、models.DO_NOTHING
        什么都不做,一切都看数据库级别的约束,注数据库级别的默认约束为RESTRICT,这个约束与django中的models.PROTECT相似

.
.
.
.

Ajax

异步提交 局部刷新
ajax不是一门新的技术并且有很多版本 我们目前学习的是jQuery版本(版本无所谓 本质一样就可以)
	

基本语法
	$.ajax({
        url:'',  // 后端地址 三种填写方式 与form标签的action一致
        type:'post',  // 请求方式 默认也是get
        data:{'v1':v1Val, 'v2':v2Val},  // 发送的数据
        success:function (args) {  // 后端返回结果之后自动触发 args接收后端返回的数据
         	 $('#d3').val(args)
                                }
    })

Content-Type

1.urlencoded
	ajax默认的编码格式、form表单默认也是
	数据格式  xxx=yyy&uuu=ooo&aaa=kkk
 	django后端会自动处理到request.POST中
    
2.formdata
	django后端针对普通的键值对还是处理到request.POST中 但是针对文件会处理到request.FILES中
	
    
3.application/json
	form表单不支持 ajax可以
	<script>
    $('#d1').click(function () {
        $.ajax({
            url:'',
            type:'post',
            data:JSON.stringify({'name':'jason','age':18}),  // 千万不要骗人家
            contentType:'application/json',
            success:function (args) {
                alert(args)
            }

        })
    })
</script>
	后端需要从request.body中获取并自己处理

ajax携带文件数据

<script>
    $('#d3').click(function () {
        // 1.先产生一个FormData对象
        let myFormDataObj = new FormData();
        // 2.往该对象中添加普通数据
        myFormDataObj.append('name', 'jason');
        myFormDataObj.append('age', 18);
        // 3.往该对象中添加文件数据
        myFormDataObj.append('file', $('#d2')[0].files[0])
        // 4.发送ajax请求
        $.ajax({
            url:'',
            type:'post',
            data:myFormDataObj,

            // ajax发送文件固定的两个配置
            contentType:false,
            processData:false,
            success:function (args){
                alert(args)
            }

        })
    })
</script>

作业

1.利用q查询进阶操作编写一个简易版本的图书查询功能
	书籍名称、书籍价格...
2.利用ajax完整一个用户名实时校验功能
3.利用ajax编写一个删除功能的二次提醒

标签:obj,models,res,查询,ORM,常用字,数据
From: https://www.cnblogs.com/tengyifan888/p/16993241.html

相关文章