ORM
1. 数据库配置
配置使用 sqlite3,MySQL,oracle,PostgreSQL 等数据库
sqlite3 数据库配置
- 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 的惰性机制:
Table.objects.all()或者. filter()语句不会运行任何的数据查询
只有调用 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 方法是从查询结果中排除某个字段
来源: https://www.cnblogs.com/yanadoude/p/12989772.html