Django-(6)

内容概览

  • 正反向查询进阶操作
  • 聚合查询
  • 分组查询
  • F与Q查询
  • ORM查询优化
  • 事务操作
  • 模型层常见字段
  • ORM常见字段参数
  • 多对多三种创建方式

正反向查询进阶操作

"""不使用给出具体条件的表作为主体查找"""
# 1.查询主键为1的书籍对应的出版社名称及书名
res = models.Publish.objects.filter(book__pk=1).values('name', 'book__title')  # 过滤条件中也支持使用正反向查询,反向查询使用表名小写

# 2.查询主键为3的书籍对应的作者姓名及书名
res = models.Author.objects.filter(book__pk=3).values('name', 'book__title')

# 3.查询jason的作者的电话号码和地址
res = models.AuthorsDetail.objects.filter(author__name='jason').values('phone', 'address')

# 4.查询南方出版社出版的书籍名称和价格
res = models.Book.objects.filter(publish_name='南方出版社').values('title', 'price')  # 正向查询使用字段名

# 5.查询jason写过的书的名称和日期
res = models.Boos.objects.filter(authors__name='jason').values('title', 'publish_time')

# 6.查询电话是111的作者姓名和年龄
res = models.Author.objects.filter(author_detail__phone=111).values('name', 'age')

# 7.查询主键为1的书籍对应的作者电话号码
res = models.Author.objects.filter(book__pk=1).values('author_detail__phone')
"""可以从任意数据查到直接或者间接关联的数据"""
res = models.AuthorDetail.objects.filter(author__book__pk=1).values('phone')

聚合函数

"""使用聚合函数前需要先导入"""
from django.db.models import Max, Min, Sum, Avg, Count
"""在没有分组前想要使用聚合函数需要关键字aggregate"""
res = models.Book.objects.aggregate(Max('price'))  # 获取最大值
res = models.Book.objects.aggregate(Min('price'))  # 获取最小值
res = models.Book.objects.aggregate(Sum('price'))  # 求和
res = models.Book.objects.aggregate(Avg('price'))  # 平均值
res = models.Book.objects.aggregate(Count('pk'))  # 统计个数

分组查询

分组有个一特性可能会导致报错,既只能够直接获取分组的字段,其他字段需要使用方法;
将sql_mode中only_full_group_by配置移除即可取消该特性

# 统计每本书的作者个数
res = models.Book.objects.annotate(author_num=Count('authors__pk')).values('author_num', 'title')
"""
在分组前不写条件会将一个个数据分组
models.Book.objects.annotate()
想要按照某个字段分组需要先指定字段
models.Book.objects.values('price').annotate()  按照价格分组
"""
# 统计出每个出版社卖的最便宜的书的价格
res = models.Publish.objects.annotate(min_price=Min('book__price')).values('min_price')

# 统计不止一个作者的图书
res = models.Book.objects.annotate(author_num=Count('authors__pk')).filter(author_num__gte=2).values('title', 'author_num')

# 查询各个作者出的书的总价格
res = models.Author.objects.annotate(total_price=Sum('book__price')).values('name', 'total_price')

F与Q查询

  • F查询:查询条件不是自定义而是来自于表中其他字段
# 使用前也需要先导入
from django.db.models import F
# 1.查询库存数大于卖出数的书籍
res = models.Book.objects.filter(storage_num__gt=F('sale_num'))

# 2.将所有书籍的价格上涨1000块
models.Book.objects.update(price=F('price') + 1000)

# 3.将所有书籍名称加上爆款后缀
"""上边方法针对字符串数据无法直接拼接"""
from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.update(title=Concat(F('title'),Value('爆款')))
  • Q查询:可以改变filter括号内多个条件之间的逻辑运算符
from django.db.models import Q
res = models.Book.objects.filter(Q(pk=1), Q(publish_id=3))  # 使用逗号还是and关系
res = models.Book.objects.filter(Q(pk=1)| Q(publish_id=3))  # 使用管道符是or关系
res = models.Book.objects.filter(~Q(pk=1)| Q(publish_id=3))  # 在前边加上波浪号是not取反

"""Q查询还可以让字符串也能作为查询条件"""
q_obj = Q()   # 先创建Q对象
q_obj.children.append(('pk', 1))
q_obj.children.append(('publish_id', 3))
res = models.Book.objects.filter(q_obj)  # 直接将对象当做查询条件即可

ORM查询优化

"""可以先将配置查看SQL代码的配置文件配好"""
django orm自带limit分页,以减轻数据库以及服务端的压力
django orm默认都是惰性查询,只有当orm语句在后续的代码中真正要使用到的时候才会执行
res = model.Book.objects.all()  # 不会执行SQL语句
print(res)  # 只有在使用到的时候才会执行SQL语句

# only:会将括号内填写的字段封装成数据对象,对象在点击其中的字段的时候不会在从数据库查询;但是也可以点击括号内没有填写的字段,查询括号内没有的字段会走数据库查询
res = models.Book.objects.only('title', 'price')
for obj in res:
    print(obj.title)
    print(obj.price)
    print(obj.publish_time)  # 查询没有封装的字段会从数据库查询
    
# defer:defer与only的作用相反,会将除括号外的字段封装,点击括号内的字段会从数据库中查询
res = models.Book.objects.defer('title', 'price')
for obj in res:
	print(obj.title)
	print(obj.price)
	print(obj.publish_time)

# select_related: 括号内只能接收外键字段(一对一、一对多),会自动连表并封装成数据对象,在点击数据对象中有的字段时就不会再从数据库中查找
res = models.Book.objects.select_related('authors')
for obj in res:
	print(obj.publish.name)

# prefetch_related:与select_related的差别在于底层使用的是子查询,将查询之后的结果封装到数据对象
res = models.Book.objects.prefetch_related('authors')
for obj in res:
	print(obj.publish.name)
"""select_related与prefetch_related的使用场景不同,占用的资源也不同"""

事务操作

使多个SQL语句要么同时成功,要么都不成功

# 先导入模块
from django.db import transaction
# 使用上下文管理器
try:  # 如果orm语句有报错则捕获
	with transaction.atomic:
		pass  # orm语句
except Exception as e:
	print(e)

模型层常见字段

AutoField()  # int自增
CharField()  # varchar
IntegerField()  # int
BigIntegerField()  # bigint
DateField()  # 日期格式
DateTimeField()  # 年月日时分秒
DecimalField()  # decimal小数
EmailField()  # 邮箱格式
BooleanField()  # 传布尔值,保存为0或1
TextField()  # 存储大段文本
FileField()  # 存储文件数据,自动找指定位置存储,字段存储具体位置
ForeignKey()
ManyToManyField()
OneToOneField()

"""ORM还支持自定义字段"""
class MyCharField(models.Field):
	def __init__(self, max_length, *args, **kwargs):
		self.max_length = max_length
		super().__init__(max_length=max_length, *arge, **kwargs)
	def db_type(self, connection):
		return f'char({self.max_length})'
info = MyCharField(max_length=32)

ORM常见字段参数

max_length					最大字符长度
verbose_name				给字段起别名
auto_now					每次更新数据都会修改为当前时间
auto_now_add				记录创建时的时间
null						设置当前字段是否能为空
default						设置当前字段默认值
max_digits,decimal_places	一般配合DecimalField使用,表示整数与小数占多少位
unique						当前字段是否是唯一
db_index					给字段建立索引
choices						提前列举出数据,添加数据时只需要选择与之对应的数据即可
	class UserInfo(models.Model):
		username = models.CharField(max_length=32)
		gender_choice = (
			(1, '男'),
			(2, '女'),
			(3, '保密')
		)
		gender = models.IntegerField(choices=gender_choice)
	# 获取对应数据要使用数据对象.get_gender_display()
to							指定绑定哪张表
to_field					指定绑定的字段
related_name				替代原来反向查询时使用的'表名小写_set'
on_delete:
	1. models.CASCADE:级联操作,主表中的一条数据删除,与之相关联的数据都被删除
	2. models.SET_NULL:设置为空,主表中的一条数据删除,与之相关联的数据都设置为null(定义外键时需要设定null=True)
	3. models.PROTECT:主表中的一条数据删除,表中相关字段受保护,不允许删除
	4. models.SET_DEFAULT:主表中的一条数据被删除,与之相关联的数据都设置为默认值(定义外键时需要设置默认值)
	5. models.SET():主表中的一条数据被删除,与之相关联的数据设置为括号内的值
	6. models.DO_NOTHING:什么都不做,一切看数据库级别的约束(数据库级别的默认约束为RESTRICT,这个约束与django中的models.PROTECT相似)

多对多三种创建方式

1. 自动创建
	authors = models.ManyToManyField(to='Autor')
	第三张表自动创建,但是第三张表扩展性差
2. 手动创建
	class Book2Author(models.Model):
		book_id = models.ForeignKey(to='Book')
		author_id = models.ForeigKey(to='Author')
	手动创建第三张表,但是无法使用正反向查询以及多对多四个方法
3. 半自动创建
	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')
	扩展性强且支持正反向操作,依然无法使用多对多四个方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值