聚合查询(aggregate)
1.在mysql中,聚合函数有:sum min max avg count
2.在orm中如何使用聚合函数
1.必须要有有关键字:aggregate
2.我们需要导模块:from django.db.models import Count, Sum, Max, Min, Avg
3. 返回的值是字典,并且aggregate()方法里可以查询多个
需求:求书籍表中得书的平均价格
from django.db.models import Avg
res = models.Book.objects.aggregate(Avg('price'))
print(res)
from django.db.models import Avg,Max,Min,Sum,Count
res = models.Book.objects.aggregate(Avg('price'),Max('price'),Min('price'),Count('pk'),Sum('price'))
print(res) # {'price__avg': 6888.2, 'price__max': Decimal('22222.00'), 'price__min': Decimal('666.00'), 'pk__count': 5, 'price__sum': Decimal('34441.00')}
分组查询(annotate)
1.在mysql中,使用分组是用group by,并且分组之后只能取得分组的依据,其他的字段不能拿到(严格模式),如果不设置这个模式,所有字段都可以都可以取到
2.设置一个严格模式:
第一种:
set global sql_mode='only_full_group_by'
第二种:在配置文件中修改
my.ini-----mac系统(my.cnf)
sql_mode='only_full_group_by'
重启Mysql的服务生效
3.在orm中如何进行分组 ---- 使用annotate()
ps:聚合函数一般与分组配合使用
4.按照表达的其他字段分组
res = models.Book.objects.values('').annotate()
5.如果在分组的时候,宝座了,很有可能是严格模式的问题,--->把严格模式去掉
1.统计每一本书的作者个数
from django.db.models import Count
res = models.Book.objects.annotate(authors_num=Count('authors__pk')).values('title','authors_num')
print(res) # <QuerySet [{'title': '自传1', 'authors_num': 2}, {'title': '自传5', 'authors_num': 0}, {'title': '自传4', 'authors_num': 0}, {'title': '自传2', 'authors_num': 2}, {'title': '自传3', 'authors_num': 0}]>
2.统计每个出版社卖的最便宜的书的价格
from django.db.models import Min
res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price')
print(res) # <QuerySet [{'name': '清华出版社', 'min_price': Decimal('666.00')}, {'name': '人民出版社', 'min_price': Decimal('22222.00')}, {'name': '新华出版社', 'min_price': Decimal('777.00')}]>
3.统计不止一个作者的图书
res = models.Book.objects.annotate(author_num=Count('authors__pk')).filter(author_num__gt=1).values('title','author_num')
print(res)
4.查询每个作者出的书的总价格
from django.db.models import Sum
res = models.Author.objects.annotate(price_sum=Sum('book__price')).values('name','price_sum')
print(res) # <QuerySet [{'name': 'nana', 'price_sum': Decimal('1443.00')}, {'name': 'cx', 'price_sum': Decimal('1443.00')}, {'name': 'xiao', 'price_sum': None}]>
F查询
1.F查询就是拿原来的值
2.用的书后需要导模块:from django.db.models import F
3.拼接(Concat)--- 导模块-->from django.db.models.functions import Concat
1.查询卖出数大于库存数的书籍
from django.db.models import F
res = models.Book.objects.filter(sale_num__lt=F('kucun')).values('title')
print(res) # <QuerySet [{'title': '自传3'}, {'title': '自传5'}]>
2.将所有书籍的价格提升500块
from django.db.models import F
models.Book.objects.update(price = F('price')+500)
3.将所有书的名称后面加上爆款两个字
1.错误写法:
update app01_book set title = title + 'haha'
models.Book.objects.update(title=F('title')+'haha'
2.正确
from django.db.models.functions import Concat
from django.db.models import F
from django.db.models import Value
models.Book.objects.update(title = Concat(F('title'),Value('_nb')))
Q查询
对于filter()方法内逗号分隔开的多个条件,都是and关系,如果想用or或者not关系,则需要使用Q,器其解决的是逻辑关系(and,or,not)
1.查询卖出数大于200或者价格小于600的书籍
from django.db.models import Q
res = models.Book.objects.filter(Q(sale_num__gt=200)|Q(price__lt=600)).values('title')
print(res)
ps:
res = models.Book.objects.filter(sale_num__gt=100, price__lt=600) # and关系
res = models.Book.objects.filter(sale_num__gt=100).filter(price__lt=600) # and关系
res = models.Book.objects.filter(Q(sale_num__gt=100), Q(price__lt=600)) # and关系
res = models.Book.objects.filter(~Q(sale_num__gt=100)|Q(price__lt=600)) # ~是非的关系
Q补充高级用法
能够以字符串作为查询字段
源码:
class Q(tree.Node):
AND = 'AND'
OR = 'OR'
default = AND
def __init__(self, *args, **kwargs):
super(Q, self).__init__(children=list(args) + list(kwargs.items()))
# 鼠标点进children里
class Node(object):
default = 'DEFAULT'
def __init__(self, children=None, connector=None, negated=False):
self.children = children[:] if children else []
self.connector = connector or self.default
self.negated = negated
''''''
# 筛选出对浏览器端对按价格排序的数据
requests.GET.get('sort') # ‘price’
res = models.Book.objects.filter(price__gt=100)
res = models.Book.objects.filter('price'+'__gt'=100)
1.q = Q()
2.q.connector = 'or' # 把多个查询条件改为OR关系了
3.q.children.append(('maichu__gt', 100))
4.q.children.append(('sale_num__lt',100))
res = models.Book.objects.filter(q) # 默认and关系 ,,
print(res)
Django中如何开启事务
1.在mysql中的事务ACID:原子性、一致性、隔离性、持久性
2.事务的作用:保证数据安全的,写在事务里面的sql语句要么全部成功,要么全部失败
3.Mysql的隔离级别:脏读、重复读
4.开启事务的步骤
1.开启事务:start transaction
2.提交事务:commit
3.回滚事务:rollback
5.在django中如何开启事务
from django.db import transaction
try:
with transaction.atomic(): # 开启
models.Book.objects.create()
models.Publish.objects.update()
# sql1
# sql2
...
except Exception as e:
print(e) # 当sql语句出现异常的时候,可以在这里打印错误信息
transaction.rollback() # 回滚
模型层中常见字段和参数
1.AutoField:int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列。
2.IntegerField:一个整数类型,范围在 -2147483648 to 2147483647。
3.CharField:字符类型,必须提供max_length参数, max_length表示字符长度。
4.DateField:日期字段,日期格式 YYYY-MM-DD,相当于Python中的datetime.date()实例。(auto_now=True,auto_now_add=True)
5.DateTimeField:日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例
6.BooleanField(Field)- 布尔值类型(性别--tinyint)
在代码里面就是要True/False------------>在数据库中存的是0/1
7.TextField(Field)- 文本类型(存大段文本)
可以存大段的文本---->当字符串比较少的时候,一般用varchar(512)
8.FileField(Field)- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
9.image = models.FileField(upload_to='文件上传的位置')
image = models.ImageField(upload_to='图片') # 只能上传图片
10.FloatField(Field)- 浮点型
11.DecimalField(Field)
- 10进制小数
- 参数:
max_digits,小数总长度
decimal_places,小数位长度
其他:https://www.yuque.com/liyangqit/lb35ya/cmatgb
ORM字段参数
1.null:用于表示某个字段可以为空。
2.unique:如果设置为unique=True 则该字段在此表中必须是唯一的 。
author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)
# 等同于:
author_detail = models.ForeignKey(unique=True, to='AuthorDetail', on_delete=models.CASCADE)
3.db_index:如果db_index=True 则代表着为此字段设置索引。
4.default:为该字段设置默认值。
5.DateField和DateTimeField
配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。
配置上auto_now=True,每次更新数据记录的时候会更新该字段。
6.verbose_name:Admin中显示的字段名称
自定义字段
class FixedCharField(models.Field):
"""
自定义的char类型的字段类
"""
def __init__(self, max_length, *args, **kwargs):
self.max_length = max_length
super(FixedCharField, self).__init__(max_length=max_length, *args, **kwargs)
def db_type(self, connection):
"""
限定生成数据库表的字段类型为char,长度为max_length指定的值
"""
return 'char(%s)' % self.max_length
class Class(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=25)
# 使用自定义的char类型的字段
cname = FixedCharField(max_length=25)