Django微讲解(七)
聚合查询
| 我们在讲数据库的聚合查询的时候,讲了数据库的聚合函数,常用就是最大值'max'、最小值'min'、求和'sum'、计数'count'、 |
| 平均值'avg',我们的Django ORM聚合查询使用的也是这些关键字,只不过数据库的聚合函数是需要分组之后才可以使用的,而Django ORM |
| 的聚合函数没有分组也可以使用聚合函数,默认整体的一个表就是一组。 |
| from django.db.models import Max,Min,Count,Sum,Avg |
| res = models.Book.objects.aggregate(Max('price')) |
| print(res) |
| 使用聚合查询的关键字是'aggregate' |
分组查询
| 数据库的分组查询使用的是group by关键字,Django ORM使用的关键字是'annotate',ORM在执行分组操作的时候,有的计算机 |
| 会报错,报错的话可以去修改'sql_mode',移除'only_full_group_by'即可。 |
| |
| res = models.Book.objects.annotate(auhtor_num=Count('authors__pk')).values('title','auhtor_num') |
| print(res) |
| |
| res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price') |
| print(res) |
| |
| res = models.Book.objects.annotate(author_count=Count('authors__pk')).filter(author_count__gte=2).values('title','author_count') |
| print(res) |
| |
| res = models.Author.objects.annotate(price_num=Sum('book__price')).values('name','price_num') |
| print(res) |
| |
| ''' |
| 上述四个练习题都是以表为单位分组的,如果想要以表中的某个字段分组,只需要在'annotate'关键字前面点'values'给某个字段进行分组即可 |
| ''' |
| res = models.Book.objects.values('publish_id').annotate(book_num=Count('pk')).values('publish_id','book_num') |
| print(res) |
往已经存在数据的表中添加字段
| 当表中已经存在数据的情况下,想要在添加额外字段,就需要指定该字段的默认值,或者指定该字段的值可以为null |
| 方式一: |
| 可以给额外添加的字段加一个默认值,关键字是'default' |
| 示例:age = models.IntegerField(default=25) |
| 方式二: |
| 设置额外添加字段的值可以为null |
| 示例:age = models.IntegerField(null=True) |
| 方式三: |
| 可以在迁移命令的提示中直接给默认值 |
F查询
| F可以帮我们取到表中某个字段对应的值来当做我们的筛选条件,而不是自定义常量的条件,实现了动态比较的效果,Django还支 |
| 持F对象之间以及F对象与常数之间的加减乘除和取模的操作。 |
| |
| from django.db.models import F |
| res = models.Book.objects.filter(kucun__gt=F('xiaoliang')) |
| print(res) |
| |
| res = models.Book.objects.update(price=F('price') + 1000) |
| print(res) |
| |
| ''' |
| 想要修改char字段的值,不可以用上述的方法,可以使用下面ORM专门提供的方法 |
| ''' |
| from django.db.models.functions import Concat |
| from django.db.models import Value,F |
| models.Book.objects.update(title=Concat(F('title'),Value('_iii'))) |
Q查询
| filter()方法中逗号隔开的条件是'and'的关系,是没有办法直接修改的,所以我们就可以使用Q对象,支持逻辑运算符,'管道 |
| 符'(|)就是'or'关系,在Q对象前面加'~'就是'not'的关系。 |
| |
| from django.db.models import Q |
| res = models.Book.objects.filter(Q(price__gt=20000)|Q(xiaoliang__gt=1000)) |
| print(res) |
| |
| res = models.Book.objects.filter(~Q(price__gte=20000)|~Q(kucun__gte=1000)) |
| print(res) |
| |
| q_obj = Q() |
| q_obj.connector = 'or' |
| q_obj.children.append(('price__gt',20000)) |
| q_obj.children.append(('kucun__gt',1000)) |
| res = models.Book.objects.filter(q_obj) |
| print(res) |
ORM查询优化
| ORM查询默认都是惰性查询,能不消耗数据库资源就不消耗,ORM查询默认自带分页功能,尽量减轻单次查询数据的压力 |
| |
| only会产生对象结果集,对象点括号内出现的字段不会再次查询数据库 |
| res = models.Book.objects.only('title','price') |
| for obj in res: |
| print(obj.title) |
| print(obj.price) |
| |
| |
| defer也会产生对象结果集,对象点括号之外的字段不会再次查询数据库 |
| res = models.Book.objects.defer('title','price') |
| for obj in res: |
| print(obj.xiaoliang) |
| |
| |
| select_related括号内只能传外键字段,只能传一对一和一对多字段,不能传多对多字段,内部原理就是直接连表,然后将连 |
| 接之后的表中所有的数据全部封装到数据对象中,然后对象就可以通过正反向查询,内部不会再次查询数据库,不会增加数据库的压力。 |
| res = models.Book.objects.select_related('publish') |
| for obj in res: |
| print(obj.title) |
| print(obj.price) |
| print(obj.publish.name) |
| print(obj.publish.addr) |
| |
| prefetch_related括号内只能传外键字段,只能传一对一和一对多字段,不能传多对多字段,内部原理是将多次查询之后的结 |
| 果封装到数据对象当中,然后对象就可以通过正反向查询,内部不会再次查询数据库,不会增加数据库的压力。 |
| res = models.Book.objects.prefetch_related('publish') |
| for obj in res: |
| print(obj.title) |
| print(obj.price) |
| print(obj.publish.name) |
| print(obj.publish.addr) |
ORM常见字段
| |
| int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列。 |
| |
| 整型int |
| |
| 字符类型,必须提供max_length参数, max_length表示字符长度,对应的是数据库中的varchar类型,没有设置对应char类型 |
| 的字段,但是Django允许我们自定义新的字段。 |
| |
| 10进制小数 |
| |
| 日期字段,日期格式 YYYY-MM-DD,相当于Python中的datetime.date()实例。 |
| |
| 日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例。 |
| |
| 整型bigint |
| |
| 传布尔值,对应的是0和1 |
| |
| 存储大段文本 |
| |
| 传文件自动保存到指定位置并存文件路径 |
| |
| 本质还是varchar类型 |
ORM重要参数
| |
| 主键 |
| |
| 字段最大长度 |
| |
| 注释 |
| |
| 是否允许为空 |
| |
| 设置默认值 |
| |
| 小数总长度 |
| |
| 小数位长度 |
| |
| 如果设置为unique=True 则该字段在此表中必须是唯一的 。 |
| |
| 如果db_index=True 则代表着为此字段设置索引。 |
| |
| 配置上auto_now=True,每次更新数据记录的时候会更新该字段。 |
| |
| 配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。 |
| |
| 用于可以被例举完全的数据 |
| |
| 设置要关联的表 |
| |
| 设置要关联的表的字段 |
| |
| 是否在数据库中创建外键约束,默认为True。 |
| ''' |
| 外键字段中使用related_name参数可以修改正向查询的字段名 |
| ''' |
| choices示例: |
| models.py文件: |
| class Info(models.Model): |
| username = models.CharField(max_length=255) |
| password = models.IntegerField() |
| gender_choies = ( |
| (1,'nan'), |
| (2,'nv'), |
| (3,'bian') |
| ) |
| gender = models.IntegerField(choices=gender_choies) |
| test.py文件: |
| res = models.Info.objects.filter(pk=1).first() |
| print(res.get_gender_display()) |
事务操作
| |
| 原子性、一致性、持久性、独立性 |
| |
| 开启事务:start transcation |
| 事务回滚:rollback |
| 确认事务:commit |
| |
| from django.db import transaction |
| try: |
| with transaction.atomic(): |
| pass |
| except Exception: |
| pass |
ORM执行原生SQL
| |
| from django.db import connection, connections |
| cursor = connection.cursor() |
| cursor = connections['default'].cursor() |
| cursor.execute("""SELECT * from auth_user where id = %s""", [1]) |
| cursor.fetchone() |
| |
| |
| models.UserInfo.objects.extra( |
| select={'newid':'select count(1) from app01_usertype where id>%s'}, |
| select_params=[1,], |
| where = ['age>%s'], |
| params=[18,], |
| order_by=['-age'], |
| tables=['app01_usertype'] |
| ) |
多对多创建方式
| |
| 全自动就是ORM自动创建第三张表,但是没有办法扩展第三张表的字段 |
| 示例:authors = models.ManyToManyField(to='Author') |
| |
| 第三张表可以完全自定义,扩展性高,但是不能使用外键方法和正反向查询 |
| 示例: |
| class Book(models.Model): |
| title = models.CharField(max_length=32) |
| class Author(models.Model): |
| name = models.CharField(max_length=32) |
| class Book2Author(models.Model): |
| book_id = models.ForeignKey(to='Book') |
| author_id = models.ForeignKey(to='Author') |
| |
| 可以使用正反向查询,第三张表还可以扩展,但是不能使用add、set、remove、clear这四种方法 |
| 示例: |
| ''' |
| 多对多建在任意一方都可以,如果建在Author表,字段顺序互换即可 |
| ''' |
| class Book(models.Model): |
| title = models.CharField(max_length=32) |
| authors = models.ManyToManyField( |
| to='Author', |
| through='Book2Author', |
| through_fields=('book','author') |
| ) |
| class Author(models.Model): |
| name = models.CharField(max_length=32) |
| class Book2Author(models.Model): |
| book = models.ForeignKey(to='Book') |
| author = models.ForeignKey(to='Author') |
这里是IT小白陆禄绯,欢迎各位大佬的指点!!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)