数据库
首页 > 数据库> > Django 数据库查询优化,choices参数(数据库字段设计常见),MVC和MTV模型,多对多三种创建方式

Django 数据库查询优化,choices参数(数据库字段设计常见),MVC和MTV模型,多对多三种创建方式

作者:互联网

数据库查询优化

orm语句的特点:惰性查询

如果仅仅只是书写了orm语句,在后面没有用到该语句所查询出来的参数,那么orm会自动识别,并不执行

举例:

res = models.Book.objects.all()
# 单单执行此语句Django并不会使用数据库,减轻数据库压力
res = models.Book.objects.all()
print(res)
# 只有用到数据了才会走数据库

2608149-20220304182304902-1951759058

接下来尝试获取数据表中所有书的名字。

res = models.Book.objects.values('name')
print(res)  # 拿到列表套字典的形式,对象
for i in res:
  print(i.get('name')) # 通过for循环字典取值方式拿到书籍名字

2608117-20220304182401815-184659158

那么如何实现获取到的是一个数据对象,再通过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)

2608117-20220304182411446-1456114505

结论:defer与only刚好相反,defer括号内放的字段不再查询出来的对象中,查询该字段需要重新走数据库。如果查询的是非括号内的字段,则不走数据库。

select_related与prefetch_related:与跨表操作有关

举例:查询每本书的的出版社名字

res = models.Book;.objects.all()
for i in res:
  print(i.publish.name)
# 使用all方法查询的时候,每一个对象都会去数据库查询数据

2608117-20220304182420073-1853526262

res = models.Book.objects.select_related()
for i in res:
  print(i.publish.name) # 只走了一次数据库, 使用INNER JOIN内连接操作

2608117-20220304182424303-1313672361

总结:select_related 内部直接先将book与publish连接,然后一次性将大表里面的所有数据全部封装给查询出来的对象。select_related括号内只能放外键字段并且是一对多,一对一。

# 跟跨表操作有关

res = models.Book.objects.prefetch_related('publish')  # 子查询
for i in res:
    print(i.publish.name)
    
"""
    prefetch_related该方法内部其实就是子查询
        将子查询查询出来的所有结果也给你封装到对象中
        给你的感觉好像也是一次性搞定的
"""

2608117-20220304182428724-1255863855

结论: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模型

多对多三种创建方式

全自动

利用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