ORM

1. 数据库配置

配置使用sqlite3,mysql,oracle,postgresql等数据库

sqlite3数据库配置

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。
DATABASES = {
    'default': {
        # 默认使用的数据库引擎是sqlite3,项目自动创建
        'ENGINE': 'django.db.backends.sqlite3',
        # 指定数据库所在的路径
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

mysql数据库配置

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',	# 表示使用mysql数据库引擎 
        'NAME': 'bwonline',        				# 数据库名字,先在mysql下创建好
        'USER': 'root',          				# 数据库账号
        'PASSWORD': '123456',      				# 数据库密码
        'HOST': '127.0.0.1',    				# 数据库IP,留空表示"localhost"
        'PORT': '3306',                   		# 数据库端口
    }
}

2. ORM表模型

一对一(one-to-one)概念:

实质就是在主外键(foreign key)的关系基础上,给外键加了一个unique=True的属性。

一对多(one-to-many)概念:

就是主外键关系(foreign key)

多对多(many-to-many)概念:

(ManyToManyField)自动创建第三张表,也可以手动创建第三张表:两个foreign key

3. ORM操作

3.1 QuerySet

QuerySet 可迭代 可切片

Django的QuerySet 对应于数据库的记录,通过设定的条件进行过滤

QuerySet 的惰性机制:

  1. Table.objects.all()或者.filter()语句不会运行任何的数据查询

  2. 只有调用QuerySet的时候才会执行SQL语句

    要真正从数据库获得数据,你可以遍历queryset或者使用if queryset,总之你用到数据时就会执行sql.
    为了验证这些,需要在settings里加入 LOGGING(验证方式)

QuerySet 的cache:

# queryset是具有cache的
     # 当你遍历queryset时,所有匹配的记录会从数据库获取,然后转换成Django的model。这被称为执行(evaluation).这些model会保存在queryset内置的cache中,这样如果你再次遍历这个queryset,你不需要重复运行通用的查询。     
obj=models.Book.objects.filter(id=3)
        # for i in obj:
        #     print(i)
                          ## models.Book.objects.filter(id=3).update(title="GO")
                          ## obj_new=models.Book.objects.filter(id=3)
        # for i in obj:
        #     print(i)   #LOGGING只会打印一次
        
# 简单的使用if语句进行判断也会完全执行整个queryset并且把数据放入cache,虽然你并不需要这些数据!为了避免这个,可以用exists()方法来检查是否有数据:
obj = Book.objects.filter(id=4)
	#  exists()的检查可以避免数据放入queryset的cache。
	if obj.exists():
		print("hello world!")
        
# 当queryset非常巨大时,cache会成为问题
	#处理成千上万的记录时,将它们一次装入内存是很浪费的。更糟糕的是,巨大的queryset可能会锁住系统进程,让你的程序濒临崩溃。要避免在遍历数据的同时产生queryset cache,可以使用iterator()方法来获取数据,处理完数据就将其丢弃。
bjs = Book.objects.all().iterator()
# iterator()可以一次只从数据库获取少量数据,这样可以节省内存
for obj in objs:
	print(obj.name)
#BUT,再次遍历没有打印,因为迭代器已经在上一次遍历(next)到最后一次了,没得遍历了
for obj in objs:
	print(obj.name)

#当然,使用iterator()方法来防止生成cache,意味着遍历同一个queryset时会重复执行查询。所以使用iterator()的时候要当心,确保你的代码在操作一个大的queryset时没有重复执行查询

总结:
queryset的cache是用于减少程序对数据库的查询,在通常的使用下会保证只有在需要的时候才会查询数据库。
使用exists()和iterator()方法可以优化程序对内存的使用。不过,由于它们并不会生成queryset cache,可能
会造成额外的数据库查询。

3.2 增

一对一信息的创建		
			|--->	create方式
			|--->	save方式
一对多信息的创建
			|--->	create方式
			|--->	save方式
多对多信息的创建
	|--->	使用model.ManyToManyField()会自动创建第三张表
	|--->	手动创建多对多信息表		
					|--->	create方式
					|--->	save方式

3.3 删

#filter返回一个QuerySet对象,filter里可以设定多个过滤条件
Book.objects.filter(id=1).delete()	

3.4 改

save()	# 将所有属性重新设定一遍,效率低
update()# 直接设置对象的属性
		# update()是QuerySet对象的一个方法
    	# get返回的是一个model对象,其没有update方法

3.5 查

all()		# 获取所有数据 支持切片操作(不支持负索引)返回QuerySet对象
get(id=1)	# 获取id=1的一组数据(若获取了多组数据,就会报错)返回model对象 
filter(sex="男") # 筛选sex="男"的数据,所有符合条件的数据都会返回,返回QuerySet对象
exclude(sex="女")# 排除sex="女"的数据,返回不符合条件的所有数据,返回QuerySet对象

3.5.1 对象查询

正向查找:子表查询主表

反向查找:主表查询子表

class Author(model.Model):
    name = models.CharField(max_length=64)
class Book(model.Model):
    bookName = models.CharField(max_length=64)
	author =  models.Foreignkey("Author",related_name="book", on_delete=model.CASCADE)
# 正向查找
book = Book.objects.get(id=1)
author = book.author
# 反向查找
author - Author.objects.get(id=1)
# 方式一:主表.子表_set() 返回QuerySet对象
author.Book_set().all()
# 方式二:通过在外键中设置related_name属性值既可
author.book.all()

3.5.2 双下划线(__)查询

条件查询与对象查询对应,是在filter,values等方法中通过__来明确查询条件

# 单表条件查询
	|---> startswith	# 指定开头的匹配条件
    |---> istartswith	# 指定开头的匹配条件(忽略大小写)
    |---> endswith		# 指定结束的匹配条件
    |---> iendswith		# 指定结束的匹配条件(忽略大小写)
    |---> lt			# 小于某个值
    |---> gt			# 大于某个值
    |---> in			# 在list中匹配
    |---> contains		# 包含
    |---> icontains		# 包含(忽略大小写)
    |---> range=(1,4)	# 在某个范围内
# 多表条件查询
	|---> #正向查找之一对一查询
    |---> #正向查找之一对多查询
    |---> #反向查找之一对多查询
    |---> #反向查找之多对多查询

3.5.3 聚合函数

# 使用聚合函数需要导入
from django.db.models import *
# Avg() 求平均值
# Count() 统计个数   参数distinct=True  去重
# Max() 获取最大值 Min() 求最小值
# Sum() 求和

聚合查询:aggregate() 返回字典

  • 格式:变量=表.objects.aggregate(聚合函数名('字段名'))
  • 默认的键名:字段名__聚合函数名

分组查询: annotate() 返回queryset对象

  • 格式:变量=表.objects.values('字段名').annotate(聚合函数名('字段名'))
  • values: 分组。类似于先筛选一遍

F查询: 专门取对象中某列值的操作 支持加减乘除操作

from django.db.models import F
Table.objects.all().updata(num=F("num")+10)

Q查询: 构建搜索条件(匹配条件)

  • Q对象可以组合使用 &| 操作符,当一个操作符用于两个Q对象时,会产生一个新的Q对象
  • 可以用 ~ 操作符放在表达式前面表示否定,也可允许否定与不否定形式的组合
  • Q对象可以与关键字参数查询一起使用,Q对象放在关键字查询参数的签名
from django.db.models import Q
Table.objects.filter(~Q(sex="男")&Q(age=18))

4. 查询数据库性能优化

1. 使用values指定查询字段避免使用all()

​ 结果是一个QuerySet ,但内部却是一个字典

2. select_related主动联表查询

​ 在第一次查询的时候,在all()前面加上一个select_related来做主动的联表查询;

​ 一次联表查询多张数据表中,格式为:select_related("table1__table2");

​ 一次联表查询一张数据表中的多个字段时,每个字段使用逗号隔开;

​ 联表查询也会降低性能。

3. prefetch_related非主动联表查询

​ prefetch_related()方法既非主动联表查询,又不会运行很多查询语句的一种方案

​ 使用prefetch_related每多查询一个字段,会在原来的基础上多查询一次数据库

4. only方法

​ 执行查询操作的时候加上only方法,其查询结果还是一个对象集合

​ 查询时加上only方法,only方法中添加哪个字段就只查询这个字段的相关数据

​ 加only参数是从查询结果中只取某个字段

5. defer方法

​ defer方法是从查询结果中排除某个字段

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄