django——模块查询操作
django——模块查询操作
目录
- 正反向查询进阶操作
- 聚合查询
- 分组查询
- F与Q查询
- ORM查询优化
- ORM常见字段类型
- ORM常见字段参数
- ORM事务操作
- 多对多三种创建方式详解
正反向查询进阶操作
① 查询主键为1的书籍对应的出版社名称及书名
res = models.Publish.objects.filter(book__pk=1).values('name','book__title')
print(res)
②查询主键为3的书籍对应的作者姓名及书名
res = models.Author.objects.filter(book__pk=1).values('name', 'book__title')
print(res)
③查询jason的作者的电话号码和地址
res = models.AuthorDetail.objects.filter(author__name='jason').values('phone','addr')
print(res)
④查询南方出版社出版的书籍名称和价格
res = models.Book.objects.filter(publish__name='南方出版社').values('title','price')
print(res)
⑤查询jason写过的书的名称和日期
res = models.Book.objects.filter(authors__name='jason').values('title','publish_time')
print(res)
⑥查询电话是110的作者姓名和年龄
res = models.Author.objects.filter(author_detail__phone=110).values('name','age')
print(res)
⑦查询主键为1的书籍对应的作者电话号码
方法1:
models.AuthorDetail.objects.filter(author__book__pk=1).values('phone')
print(res)
方法2:
res = models.Author.objects.filter(book__pk=1).values('author_detail__phone')
print(res)
总结:正反向的进阶操作就是可以将正反向通过不同的方式查询到该查询到的信息
看所使用的对象是否包含外键来确定正反向,包含则为正向,不包含则为反向
正向可直接通过外键=的形式获取应获取的值,反向可通过字母小写双下 等于 的形式获取
其他查询方式
聚合查询
聚合查询是指对一个数据表(Model)中某个字段的数据进行部分或者全部统计查询的一种方式
-
聚合函数
函数 作用 Max 求最大值 Min 求最小值 Sum 求总和 Avg 求平均值 Count 求个数 -
使用聚合函数时,需要先导入模块,才能使用
from django.db.models import Max, Min, Sum, Avg, Count
-
没有分组之前如果单纯的时候聚合函数 需要关键字aggregate
res = models.Book.objects.aggregate(Max('price'), Min('price'), Sum('price'), Avg('price'), Count('pk')) print(res)
即为分别求书的最大价格,最小价格,价格之和,平均价格,书的个数
分组查询
-
分组查询的特性
分组有一个特性 默认只能够直接获取分组的字段 其他字段需要使用方法
我们也可以忽略掉该特性 将sql_mode中only_full_group_by配置移除即可 -
分组的方法
1.可按照整条数据分组
models.表名.objects.annotate()
按照一条条表中的记录分组
2.按照表中的某个字段分组()
models.表名.objects.values('字段名').annotate()
按照annotate之前values括号中指定的字段分组
-
分组的事例
①统计每一本书的作者个数.
1. 按照整条数据分组 res = models.Book.objects.annotate(author_num=Count('authors__pk')).values('title', 'author_num') print(res) 2. 按照表中的某个字段分组 res1 = models.Book.objects.values('publish_id').annotate(book_num=Count('pk')).values('publish_id','book_num') print(res1)
②统计出每个出版社卖的最便宜的书的价格
res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name', 'min_price') print(res)
③统计不止一个作者的图书
res = models.Book.objects.annotate(author_num=Count('authors__pk')).filter(author_num__gt=1).values('title','author_num') print(res)
filter在annotate前面则是where 在annotate后面则是having
④查询各个作者出的书的总价格
res = models.Author.objects.annotate(book_sum_price = Sum('book__price')).values('name','book_sum_price') print(res)
F与Q查询
F查询
查询条件不是自定义的,而是来自于表中其他字段
-
使用F查询时需要提前导入模块
from django.db.models import F
Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。
-
举例说明
①查询库存数大于卖出数的书籍
res = models.Book.objects.filter(storage_num__gt=F('sale_num')) print(res)
②将所有书籍的价格上涨1000块
models.Book.objects.update(price=F('price') + 1000)
③将所有书籍名称加上爆款后缀
models.Book.objects.filter(pk=5).update(title=F('title') + '爆款') # 针对字符串数据无法直接拼接 如果让字符串的数据完成拼接需要导入 Concat 和 Value from django.db.models.functions import Concat from django.db.models import Value ret3 = models.Book.objects.filter(pk=5).update(title=Concat(F('title'), Value('爆款')))
Q查询
Q查询 可以将filter()等方法中的括号内多个条件之间的逻辑运算符,还可以将查询条件的字段改为字符串的形式
-
使用Q查询时,需要提前导入模块
from django.db.models import Q
-
Q查询的用法
1.可以改变filter()等方法中的括号内多个条件之间的逻辑运算符
models.BOOK.objects.filter(Q(pk=1), Q(publish=3)) 逗号分割逻辑运算符为and models.BOOK.objects.filter(Q(pk=1)| Q(publish=3)) 管道符分割逻辑运算符为or models.BOOK.objects.filter(~Q(pk=1)| Q(publish=3)) 波浪号逻辑运算符为not
2.查询条件的字段改为字符串的形式
将查询条件改为字符串形式可以完成灵活的搜索功能
q_obj = Q() q_obj.connector = 'or' # q对象默认的多个条件的关系也是and,可更改默认条件为or q_obj.children.append('pk',1) q_obj.children.append('publish_id',1) res = models.Book.objects.filter(q_obj) print(res)
ORM查询优化
-
ORM查询的特点
1.django orm默认都是惰性查询
当orm的语句在后续的代码中真正需要使用的时候才会执行
2.django orm自带limit分页
减轻数据库端以及服务端的压力
-
only和defer
①only
res = models.Book.objects.only('title','price') for obj in res: print(obj.title) print(obj.price) print(obj.publish_time)
only会将括号内填写的字段封装成一个个数据对象 对象在点击的时候不会再走数据库查询
但是对象也可以点击括号内没有的字段 只不过每次都会走数据库查询②defer
res = models.Book.objects.defer('title', 'price') for obj in res: # print(obj.title) # print(obj.price) print(obj.publish_time)
defer与only刚好相反
数据对象点击括号内出现的字段 每次都会走数据库查询
数据对象点击括号内没有的字典 不会走数据库查询 -
select_related和 prefetch_related
res = models.Book.objects.all() for obj in res: print(obj.publish.name) # 频繁走数据库查询
频繁走数据库查询,容易造成数据库的崩溃
①select_related
res = models.Book.objects.select_related('authors') for obj in res: print(obj.authors.name) """select_related 会在内部自动拼表,会将所点的表和外键所关联的表拼到一起,只要数据在这两个表中,则不用再走数据库即可查询"""
select_related括号内只能接收外键字段(一对多 一对一) 自动连表 得出的数据对象在点击表中数据的时候都不会再走数据库查询
② prefetch_related
res = models.Book.objects.prefetch_related('publish') for obj in res: print(obj.publish.name)
prefetch_related底层其实是子查询 将查询之后的结果也一次性封装到数据对象中 用户在使用的时候是感觉不出来的
当多表查询时,数据额较大用 prefetch_related,数据额小的时候使用select_related
模型层常见字段
常见字段 | 作用 |
---|---|
AutoField() | int自增列,必须填入参数 primary_key=True |
CharField( ) | 字符类型 必须提供max_length参数, max_length表示字符长度 |
IntegerField() | 整数列(有符号的) |
BigIntegerField() | bigint自增列,必须填入参数 primary_key=True |
DateField() | 日期格式 |
DateTimeField() | 日期+时间格式 |
DecimalField() | 10进制小数 参数 : max_digits,小数总长度 decimal_places,小数位长度 |
EmailField() | 字符串类型,Django Admin以及ModelForm中提供验证机制 |
BooleanField() | 布尔值类型 传布尔值存数字0或1 |
TextField() | 存储大段文本 |
FileField() | 存储文件数据 自动找指定位置存储 字段存具体路径 参数: upload_to = "" 上传文件的保存路径 storage = None 存储组件 |
ForeignKey() | 外键字段,一对多 |
OneToOneField() | 外键字段,一对一 |
ManyToManyField() | 外键字段,多对多 |
-
常见字段的对应关系
常见字段 对应关系 AutoField integer AUTO_INCREMENT BigAutoField 'bigint AUTO_INCREMENT' BinaryField longblob BooleanField bool CharField varchar(%(max_length)s) CommaSeparatedIntegerField varchar(%(max_length)s)
'DateField': 'date',DateField date DateTimeField datetime DecimalField 'numeric(%(max_digits)s,
%(decimal_places)s)'DurationField 'bigint' FileField varchar(%(max_length)s) FilePathField varchar(%(max_length)s) FloatField double precision IntegerField integer BigIntegerField bigint IPAddressField char(15) GenericIPAddressField char(39) NullBooleanField bool OneToOneField integer PositiveIntegerField integer UNSIGNED PositiveSmallIntegerField smallint UNSIGNED SlugField varchar(%(max_length)s) SmallIntegerField smallint TextField longtext TimeField time UUIDField char(32) -
ORM还支持自定义字段
class MyCharField(models.Field): def __init__(self, max_length, *args, **kwargs): self.max_length = max_length super().__init__(max_length=max_length, *args, **kwargs) def db_type(self, connection): return 'char(%s)' % self.max_length info = MyCharField(max_length=32)
ORM常见字段参数
字段参数 | 作用 |
---|---|
max_length | 最大长度 |
verboses_name | 在后台显示对对应的名称(起别名) |
auto_now | 配置上auto_now=True 每次更新数据记录的时候会更新该字段。 |
auto_now_add | 配置auto_now_add=True 创建数据记录的时候会把当前时间添加到数据库。 |
null | 用于表示某个字段可以为空 |
default | 为该字段设置默认值。 |
max_digits | 数字允许的最大位数 |
decimal_places | 小数的最大位数 |
unique=True | 该字段在此表中必须是唯一的 |
db_index=True | 代表着为此字段设置索引 |
外键字段 | |
to | 设置要关联的表 |
to_field | 设置要关联的表的字段 |
on_delete | 当删除关联表中的数据时,当前表与其关联的行的行为。 |
related_name | 能够改变正反向查询时的口诀,类似于重命名 只不过正反向查询使用重命名来操作 |
on_delete | 级联删除 |
-
删除关联数据,与之关联也删除
1、models.CASCADE 级联操作,当主表中被连接的一条数据删除时,从表中所有与之关联的数据同时被删除 2、models.SET_NULL 当主表中的一行数据删除时,从表中所有与之关联的数据的相关字段设置为null,此时注意定义外键时,这个字段必须可以允许为空 3、models.PROTECT 当主表中的一行数据删除时,由于从表中相关字段是受保护的外键,所以都不允许删除 4、models.SET_DEFAULT 当主表中的一行数据删除时,从表中所有相关的数据的关联字段设置为默认值,此时注意定义外键时,这个外键字段应该有一个默认值 5、models.SET() 当主表中的一条数据删除时,从表中所有的关联数据字段设置为SET()中设置的值,与models.SET_DEFAULT相似,只不过此时从表中的相关字段不需要设置default参数 6、models.DO_NOTHING 什么都不做,一切都看数据库级别的约束,注数据库级别的默认约束为RESTRICT,这个约束与django中的models.PROTECT相似
-
字段数据的可能性是可以完全列举出来的时候可以使用 choices参数
如:
class UserInfo(models.Model): username = models.CharField(max_length=32) gender_choice = ( (1, '男性'), (2, '女性'), (3, '其他'), ) gender = models.IntegerField(choices=gender_choice) userinfo_obj.get_gender_display()
事务操作
-
什么是事务
将多个sql语句操作变成原子性操作,要么同时成功,有一个失败则里面回滚到原来的状态,保证数据的完整性和一致性(NoSQL数据库对于事务则是部分支持)
-
原生SQL与在模块的用法
原生SQL: start transaction\rollback\commit\savepoint
模块中需要先导入
from django.db import transaction
try:
with transaction.atomic():
pass # 多条ORM语句
except Exception as e:
print(e)
多对多三种创建方式
-
自动创建
authors = models.ManyToManyField(to='Author')
优点:第三张表自动创建
缺点:第三张表扩展性差 -
手动创建
class Book(models.Model): pass class Author(models.Model): pass class Book2Author(models.Model): book_id = models.ForeignKey(to="Book") author_id = models.ForeignKey(to="Author")
优点:第三张表扩展性强
缺点:无法使用正反向查询以及多对多四个方法
-
半自动创建
class Book(models.Model): authors = models.ManyToManyField(to='Author', through='Book2Author' through_fields=('book_id','author_id') ) class Author(models.Model): pass class Book2Author(models.Model): book_id = models.ForeignKey(to="Book") author_id = models.ForeignKey(to="Author")
优点:扩展性强并且支持正反向查询 缺点:无法使用多对多四个方法
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)