Django 数据库查询优化,choices参数(数据库字段设计常见),MVC和MTV模型,多对多三种创建方式
2022/3/7 2:15:24
本文主要是介绍Django 数据库查询优化,choices参数(数据库字段设计常见),MVC和MTV模型,多对多三种创建方式,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
数据库查询优化
orm语句的特点:惰性查询
如果仅仅只是书写了orm语句,在后面没有用到该语句所查询出来的参数,那么orm会自动识别,并不执行
举例:
res = models.Book.objects.all() # 单单执行此语句Django并不会使用数据库,减轻数据库压力
res = models.Book.objects.all() print(res) # 只有用到数据了才会走数据库
接下来尝试获取数据表中所有书的名字。
res = models.Book.objects.values('name') print(res) # 拿到列表套字典的形式,对象 for i in res: print(i.get('name')) # 通过for循环字典取值方式拿到书籍名字
那么如何实现获取到的是一个数据对象,再通过title就能够拿到书名,并且没有其他字段。
only与defer
only
res1 = models.Book.objects.only('name') # 对象只有name属性 for b in res1: print(b.name) # 如果(.)only括号内有的字段则不走数据库 print(b.title) # 如果(.)only括号内没有的字段则需要反复前往数据库查询数据,再一个一个返回,而all()不需要
结论:因为all()拿到的是所有的数据对象,而only()只拿到括号内指定的数据对象。
defer
res = models.Book.objects.defer('name') # 对象除了没有name属性之外其他的都有 for i in res: print(i.price)
结论:defer与only刚好相反,defer括号内放的字段不再查询出来的对象中,查询该字段需要重新走数据库。如果查询的是非括号内的字段,则不走数据库。
select_related与prefetch_related:与跨表操作有关
select_related
举例:查询每本书的的出版社名字
res = models.Book;.objects.all() for i in res: print(i.publish.name) # 使用all方法查询的时候,每一个对象都会去数据库查询数据
res = models.Book.objects.select_related() for i in res: print(i.publish.name) # 只走了一次数据库, 使用INNER JOIN内连接操作
总结:select_related 内部直接先将book与publish连接,然后一次性将大表里面的所有数据全部封装给查询出来的对象。select_related括号内只能放外键字段并且是一对多,一对一。
prefetch_related
# 跟跨表操作有关 res = models.Book.objects.prefetch_related('publish') # 子查询 for i in res: print(i.publish.name) """ prefetch_related该方法内部其实就是子查询 将子查询查询出来的所有结果也给你封装到对象中 给你的感觉好像也是一次性搞定的 """
结论:prefetch_related该方法内部其实就是子查询,将子查询出来的所有结果封装到对象中。
总结:select_related与prefetch_related,select_related是连表操作,prefetch_related是子查询,各有优点与缺点,如果表很大的时候,使用select_related连表耗时会耗费很长时间,而select_related子查询虽然查询两次,但是操作两个表的时间非常短效率就会胜于联表查询prefetch_related
choices参数(数据库字段设计常见)
针对信息来源可概括全部场景。比如:性别,学历,工作经验,信息来源... 这种情况该如何存储?
只要是某个字段的可能性是可以列举完全的,一般情况下都会采用choices参数
字段创建的数据类型根据想要指定字段中一个元祖元素是什么类型。该gender字段存的还是数字,但是如果存的数字在上面元祖列举的范围之内,那么可以获取到数字对应的真正的内容。
举例:
# 如果gender字段存的数字不再上述元祖列举的范围内容 # 如果在,如何获取对应的中文信息?
创建表:
class Client(models.Model): username = models.CharField(max_length=32) age = models.IntegerField() # 性别 gender_choices = { (1, '男'), (2, '女'), (3, '其他'), } """ 字段创建的数据类型根据想要指定字段中一个元祖元素是什么类型。 该gender字段存的还是数字,但是如果存的数字在上面元祖列举的范围之内 那么可以获取到数字对应的真正的内容 """ gender = models.IntegerField(choices=gender_choices)
创建数据,tests.py:
from django.test import TestCase # Create your tests here. import os import sys if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day06.settings") import django django.setup() from app01 import models models.Client.objects.create(username='junjie',age=18,gender=1) models.Client.objects.create(username='nn',age=1,gender=2) models.Client.objects.create(username='jason',age=58,gender=3) models.Client.objects.create(username='tom',age=99,gender=4)
可以看到,数据的创建是没有问题,没有创建的数字也能存。
那么取?
# 取 user_obj = models.Client.objects.filter(pk=1).first() print(user_obj.gender) # 输出:1
此时输出不应该是pk=1所对应的真正性别,怎么获取的数据是1?
只要是choices参数的字段,如果想要获取对应信息,固定写法get_字段名_display()
user_obj = models.Client.objects.filter(pk=1).first() print(user_obj.get_gender_display()) # 输出:男
那么还有一个用户名为tom
没有书写固定关系,他返回的会是什么?
user_obj = models.Client.objects.filter(pk=4).first() print(user_obj.get_gender_display()) # 输出:4
如果没有对应关系,字段是什么还是展示什么。
字符串格式也是如此:
先创建字段:
score_choices = ( ('A','优秀'), ('B','及格'), ('C','不及格'), ) # 在已创建的表中添加新的字段,需要设置null=True 表示该字段为空,也可以设置默认值 score = models.CharField(max_length=32,choices=score_choices,null=True)
添加数据:
models.Client.objects.filter(pk=1).update(score='A')
获取数据:
res = models.Client.objects.filter(pk=1).first() print(res.get_score_display()) # 输出:优秀
MVC和MTV模型
-
MTV: Django号称是MTV模型,本质也是MVC模型
M: models
T: templates
V: views -
MVC
M: models
V: views
C: controller(控制器)
多对多三种创建方式
- 全自动
- 优点: 代码不需要写,方便,支持orm提供操作第三张关系表的方法...
- 缺点: 第三张关系表的扩展性极差(没办法添加额外的字段)
- 纯手动
- 优点: 第三张表完全取决于自己额外的扩展
- 缺点: 需要写的代码加多,不能使用orm提供的简单方法,正反向查询之类...
- 半自动
全自动
利用orm自动创建第三张关系表
class Book(models.Model): name = models.CharField(max_length=32) authors = models.ManyToManyField('Author') class Author(models.Model): name = models.CharField(max_length=32)
纯手动
class Book(models.Model): name = models.CharField(max_length=32) class Author(models.Model): name = models.CharField(max_length=32) class Book2Author(models.Model): authors_id = models.ForeignKey(to='Author') books_id = models.ForeignKey(to='Book')
半自动
through_fields 字段先后顺序,判断的本质: 通过第三张表查询对应的表,需要用到那个字段酒吧哪个字段放前面,当前表是谁,就把对应的关联字放在前面。
半自动:可以使用orm正反向查询,但是没办法使用add,remove,clear,set 方法
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) class Book2Author(models.Model): authors = models.ForeignKey(to='Author') books = models.ForeignKey(to='Book') ...
总结:全自动和半自动需要掌握,为了拓展性更高一般都采用半自动
这篇关于Django 数据库查询优化,choices参数(数据库字段设计常见),MVC和MTV模型,多对多三种创建方式的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-24MongoDB资料:新手入门完全指南
- 2024-12-20go-zero 框架的 RPC 服务 启动start和停止 底层是怎么实现的?-icode9专业技术文章分享
- 2024-12-19Go-Zero 框架的 RPC 服务启动和停止的基本机制和过程是怎么实现的?-icode9专业技术文章分享
- 2024-12-18怎么在golang中使用gRPC测试mock数据?-icode9专业技术文章分享
- 2024-12-15掌握PageRank算法核心!你离Google优化高手只差一步!
- 2024-12-15GORM 中的标签 gorm:"index"是什么?-icode9专业技术文章分享
- 2024-12-11怎么在 Go 语言中获取 Open vSwitch (OVS) 的桥接信息(Bridge)?-icode9专业技术文章分享
- 2024-12-11怎么用Go 语言的库来与 Open vSwitch 进行交互?-icode9专业技术文章分享
- 2024-12-11怎么在 go-zero 项目中发送阿里云短信?-icode9专业技术文章分享
- 2024-12-11怎么使用阿里云 Go SDK (alibaba-cloud-sdk-go) 发送短信?-icode9专业技术文章分享