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')
...
总结:全自动和半自动需要掌握,为了拓展性更高一般都采用半自动
标签:name,models,res,数据库,MTV,related,Django,objects,查询 来源: https://www.cnblogs.com/xiejunjie8888/p/15973695.html