【2022.9.6】Django框架之(正反向查询进阶操作、聚合查询、分组查询、F与Q查询、ORM查询优化、ORM常见字段类型、ORM常见字段参数、ORM事物操作、多对多三种创建方式详细)

学习内容概要

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

内容详细

正反向查询进阶操作

  • 本质:就是直接用正反向查询跨表去查询数据
# 1.查询主键为1的书籍对应的出版社名称及书名
res = models.Publish.objects.filter(book__pk=1).values('name','book__title')
# print(res)

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

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

# 4.查询南方出版社出版的书籍名称和价格
res = models.Book.objects.filter(publish__name='南方出版社').values('title','price')
# print(res)

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

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

# 7.查询主键为1的书籍对应的作者电话号码
res = models.AuthorDetail.objects.filter(author__book__pk=1).values('phone')
# print(res)
res = models.Author.objects.filter(book__pk=1).values('author_detail__phone')
print(res)

聚合查询

  • 1、MySQL中的聚合函数:
    • max、min、sum、avg、count
  • 2.关键字:aggregate
from django.db.models import Max,Min,Sum,Avg,Count

res = models.Book.objects.aggregate(Max('price'),Min('price'),Sum('price'),Avg('price'),Count('PK'))
print(res)



分组查询

  • 关键字:annotate
"""
分组有一个特性 默认只能够直接获取分组的字段 其他字段需要使用方法
我们也可以忽略掉该特性 将sql_mode中only_full_group_by配置移除即可
"""
'''分组查询'''
 # 示例1:统计每一本书的作者个数
res = models.Book.objects.annotate(author_num=Count('authors__pk')).values('title', 'author_num')
print(res)
res1 = models.Book.objects.values('publish_id').annotate(book_num=Count('pk')).values('publish_id','book_num')
print(res1)
"""
    1.按照整条数据分组
        models.Book.objects.annotate()  按照一条条书籍记录分组
    2.按照表中某个字段分组()
        models.Book.objects.values('title').annotate()  按照annotate之前values括号中指定的字段分组
"""

# 示例2:统计出每个出版社卖的最便宜的书的价格
res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name', 'min_price')
# print(res)

# 示例3:统计不止一个作者的图书
'''filter在annotate前面则是where 在annotate后面则是having'''
res = models.Book.objects.annotate(author_num=Count('authors__pk')).filter(author_num__gt=1).values('title','author_num')
# print(res)

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


F查询

  • 1、F查询:查询条件不是自定义的而是来自于表中其他字段
from django.db.models import F
# 1.查询库存数大于卖出数的书籍
res = models.Book.objects.filter(storage_num__gt=F('sale_num'))
# print(res)
# 2.将所有书籍的价格上涨1000块
models.Book.objects.update(price=F('price') + 1000)
# 3.将所有书籍名称加上爆款后缀
models.Book.objects.filter(pk=5).update(title=F('title') + '爆款')  # 针对字符串数据无法直接拼接
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查询

  • 1、Q查询:可以改变filter括号内多个条件之间的逻辑运算符
  • 2、Q查询:还可以将查询条件的字段改为字符串形式
 '''Q查询:可以改变filter括号内多个条件之间的逻辑运算符'''
from django.db.models import Q
res = models.Book.objects.filter(pk=1, publish_id=3)  # 默认是and关系
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关系
print(res.query)
    '''Q查询:还可以将查询条件的字段改为字符串形式'''
q_obj = Q()
q_obj.connector = 'or'  # q对象默认的多个条件也是and关系 可以修改为or
q_obj.children.append(('pk', 1))
q_obj.children.append(('publish_id', 3))
res = models.Book.objects.filter(q_obj)
print(res)




ORM查询优化

django orm默认都是惰性查询
	当orm的语句在后续的代码中真正需要使用的时候才会执行
django orm自带limit分页
	减轻数据库端以及服务端的压力
  
res = models.Book.objects.only('title','price')
for obj in res:
     print(obj.title)
     print(obj.price)
     print(obj.publish_time)
    """
    only会将括号内填写的字段封装成一个个数据对象 对象在点击的时候不会再走数据库查询
    但是对象也可以点击括号内没有的字段 只不过每次都会走数据库查询
    """
res = models.Book.objects.defer('title', 'price')
for obj in res:
    # print(obj.title)
    # print(obj.price)
    print(obj.publish_time)
    """
    defer与only刚好相反 
        数据对象点击括号内出现的字段 每次都会走数据库查询
        数据对象点击括号内没有的字典 不会走数据库查询
    """
 
'''ORM查询优化之select_related与prefetch_related'''
res = models.Book.objects.all()
for obj in res:
     print(obj.publish.name)  # 频繁走数据库查询

res = models.Book.objects.select_related('authors')
"""
    select_related括号内只能接收外键字段(一对多 一对一) 自动连表 得出的数据对象在点击表中数据的时候都不会再走数据库查询
    """
for obj in res:
     print(obj.publish.name)
"""
    prefetch_related底层其实是子查询 将查询之后的结果也一次性封装到数据对象中 用户在使用的时候是感觉不出来的
    """
res = models.Book.objects.prefetch_related('publish')
for obj in res:
    print(obj.publish.name)


事物操作

事务:ACID
1.原子性
2.一致性
3.隔离性
4.持久性
事务隔离级别:脏读 幻读 不可重复读 ...
原生SQL: start transaction\rollback\commit\savepoint 

from django.db import transaction
try:
    with transaction.atomic():
        pass  # 多条ORM语句
except Exception as e:
        print(e)



模型层常见字段(models.py)

AutoField()
CharField()
IntegerField()
BigIntegerField()
DateField()
DateTimeField()
DecimalField()
EmailField()
BooleanField()
	传布尔值存数字01
TextField()
	存储大段文本
FileField()
	存储文件数据  自动找指定位置存储 字段存具体路径
ForeignKey()
OneToOneField()
ManyToManyField()
    
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常见字段参数

  • 1.普通字段参数
max_length
verboses_name
auto_now
auto_now_add
null
default
max_digits
decimal_places
unique=True
db_index=True
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()



  • 2、外键字段参数
to  # 设置要关联的表
to_field  # 设置要关联的表的字段
related_name  # 给外键字段 起别名
on_delete  # 当删除关联表中的数据时,当前表与其关联的行的行为  on_update 级联更新 Django默认性质自带 无需填写
    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相似






多对多三种创建方式

1.自动创建
	authors = models.ManyToManyField(to='Author')
	优点:第三张表自动创建
 	缺点:第三张表扩展性差
2.手动创建
	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")
 	优点:第三张表扩展性强
  	缺点:无法使用正反向查询以及多对多四个方法
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")
   	优点:扩展性强并且支持正反向查询
  	 缺点:无法使用多对多四个方法



posted @   W日常  阅读(71)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示