单表查询,多表查询,分组查询,聚合函数,F与Q
一、单表查询前期准备
1、新建数据库修改django默认配置数据库
去django项目下的settings修改数据库参数
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'day53', # 写你自己的数据库 'USER': 'root', 'PASSWORD': '123456', # 写你自己的密码 'HOST': '127.0.0.1', 'POST': 3306, 'CHARSET': 'utf8' } }
2、去项目app应用下或者与项目同名同名文件下的__init__文件下修改数据库
import pymysql pymysql.install_as_MySQLdb()
3、创建数据
from django.db import models # Create your models here. class Movie(models.Model): title = models.CharField(max_length=64) price = models.DecimalField(max_digits=8, decimal_places=2) publish_time = models.DateField() # 年月日 # publish_time = models.DateTimeField() # 年月日 时分秒 ''' auto_now:每次修改数据的时候 都会自动将最新的更新时间记录下来 auto_now_add:只有在创建数据的将创建时候自动记录下来 之后不会自动改变 ''' def __str__(self): # 为了演示的效果更好,我们用这个方法 return self.title # 这个方法在print时触发 我们让它返回自己的title
注意:记得创建好数据字段之后一定要同步到数据库中
python manage.py makemigrations
python manage.py migrate
4、创建测试单个文件的测试环境
随便在一个文件下去添加测试环境都可以,这里就有一个默认的tests文件,我们就在这里添加,你也可以自己手动创建文件然后添加测试环境
from django.test import TestCase # Create your tests here. import os import sys if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day53.settings") import django django.setup() from app01 import models models.Movie.objects.all()
二、单表查询
''' 单表查询必知必会16条 1、create() 2、all() 3、filter() 4、update() 5、delete() 6. first() 7. last() 8.get() 9.values() 10.values_list() 11.order_by() 12.count() 13.exclude() 14.exists() 15.distinct() 16、reverse() '''
1、create
# 1、create 增 返回值就是当前被创建数据的对象本身 # 日期可以手动给 models.Movie.objects.create(title='3D肉蒲团', price=999.23, publish_time='2016-1-1') # 还可以直接传日期对象 from datetime import date ctime = date.today() models.Movie.objects.create(title='西游记', price=666.66, publish_time=ctime) #这里我已经添加过很多数据啦,就不一一演示啦
2、all
# 2、all 查 拿到的是queryset对象 res = models.Movie.objects.all() print(res)
3、filter
# 3、filter 拿到的是queryset对象 res = models.Movie.objects.filter(id=1) res = models.Movie.objects.filter(pk=1) res = models.Movie.objects.filter(pk=1, title='python从入门到放弃') # 括号内可以放多个条件默认是and关系 # # pk指代的就是当前表的主键的字段名 可以自动查找非常方便 # # 只要是queryset 对象 就可以通过 点query 方式查看到获取当前对象内部的SQL语句 print(res.query)
4、get
# 4、get 直接获取对象本身 当查询条件不存在时不推荐使用会报错 res = models.Movie.objects.get(pk=1) print(res) print(res.title) print(res.price) res = models.Movie.objects.get(pk=1000)
5、values
# 5、values queryset对象 [{},{},{}] res = models.Movie.objects.values('title', 'publish_time') print(res)
6、values_list
# 6、values_list queryset对象 [(),(),()] 获取指定字段对应的数据 res = models.Movie.objects.values_list('title', 'price') print(res)
7、first
# 7、first 数据对象 取第一个元素对象 res = models.Movie.objects.filter().first() print(res)
8、last
# 8、last 数据对象 取最后一个元素对象 res = models.Movie.objects.filter().last() res = models.Movie.objects.last() #也可以简写 print(res)
9、update
9、update 返回值是受影响的行数 res = models.Movie.objects.filter(pk=2).update(title='金瓶mei22') print(res)
10、delete
# 10、delete res = models.Movie.objects.filter(pk=2).delete() print(res)
11、count
# 11、count 统计数据条数 res = models.Movie.objects.filter(pk=1).count() print(res)
12、order_by
# 12、order_by 按照指定的字段排序 默认是升序 加个-是降序 # res = models.Movie.objects.order_by('price') res = models.Movie.objects.order_by('-price') print(res)
13、exclude
# 13、exclude 排除什么字段之外的数据 res = models.Movie.objects.exclude(pk=1) print(res)
14、exists
# 14、exists 判断前面的对象是否有数据 返回的是布尔值 res = models.Movie.objects.filter(pk=1000).exists() print(res)
15、reverse
# 15、reverse 反转 res = models.Movie.objects.order_by().reverse() print(res)
16、distinct
# 16、distinct 去重的前提必须是有完全一样的数据才可以 # res = models.Movie.objects.all().distinct() res = models.Movie.objects.values('title', 'price').distinct() # 要指定数据类型之后可以去重 print(res)
三、神奇的双下划线查询
# 1、查询价格大于200的电影 # res = models.Movie.objects.filter(price__gt=200) # __gt代表大于 # print(res) # # 2、查询介个小于500电影 # res = models.Movie.objects.filter(price__lt=500) # __lt代表小于 # print(res) # # 3、查询价格大于等于876.23的电影 # res = models.Movie.objects.filter(price__gte=876.23) # __gte代表大于等于 # print(res) # 4、查询价格小于等于876.23的电影 # res = models.Movie.objects.filter(price__lte=876.23) # print(res) # 5、查询价格是123 或666 或876 # res = models.Movie.objects.filter(price__in=[123, 666, 876]) # print(res) # 6、查询介个在200到900之间的电影 注意这个顾头也顾尾 # res = models.Movie.objects.filter(price__range=(200, 900)) # print(res) # 7、查询电影名中包含字母p的电影 ''' 模糊查询: 关键字:like 关键符号: % :任意个数任意字符 _ : 单个任意字符 ''' res = models.Movie.objects.filter(title__contains='P') # 默认区分大小写 res = models.Movie.objects.filter(title__icontains='P') # i代表ignore加了以后忽略大小写 # 8、查询2014年出版的电影 res = models.Movie.objects.filter(publish_time__year=2014) print(res) # 9、查询电影是1月份出版的电影 res = models.Movie.objects.filter(publish_time__month=1) print(res)
四、图书管理系统表的创建以及数据录入
1、创建类
from django.db import models
class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8, decimal_places=2) publish_time = models.DateField(auto_now_add=True) # 加上auto_now_add=True该字段新增数据自动添加 # 书籍与出版社 一对多 外键字段建在多的一方 publish = models.ForeignKey(to='Publish') # 书籍与作者 多对多 外键字段建在任意一方均可 这里推荐你建在查询频率高的表上 authors = models.ManyToManyField(to='Author') def __str__(self): return self.title class Publish(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=64) class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() # 作者与作者详情表 一对一 外键字段建在任意一方均可 同样推荐建在查询频率高的表上 author_detail = models.OneToOneField(to='AuthorDetail') class AuthorDetail(models.Model): phone = models.BigIntegerField() addr = models.CharField(max_length=32)
注意:记得创建好数据字段之后一定要同步到数据库中
python manage.py makemigrations
python manage.py migrate
# 然后自己去navicate中添加些数据
五、外键字段的增删改查
我们把这个外键字段分为两类
1、一对多的增删改查
# 一对多 publish # # 1、增 方式一直接写实际的表字段publish_id # models.Book.objects.create(title='三国演义', price=123.23, publish_id=2) # # # 2、增 方式二 # publish_obj = models.Publish.objects.get(pk=1) # models.Book.objects.create(title='金瓶MEI', price=66.66, publish=publish_obj) # 查 # 改 # models.Book.objects.filter(pk=1).update(publish_id=3) # publish_obj = models.Publish.objects.get(pk=4) # models.Book.objects.filter(pk=1).update(publish=publish_obj) # 删 ''' 外键字段在1.x版本中默认的是级联更新删除的 2.x版本中 则需要你自己手动去指定 参考博客: https://www.cnblogs.com/bladecheng/p/11629061.html '''
2、多对多的增删改查
# 1、给书籍绑定作者关系 add # book_obj = models.Book.objects.filter(pk=1).first() # 拿到书对象中的第一本书 # # 书籍和作者的关系是由第三方表决定 也就意味着你要操作第三方表 # print(book_obj.authors) # 这句话就意味着书籍对象点虚拟字段authors就类似于已经跨到书籍和作者的第三方表中去了 # 然后给书籍和作者之间添加关系 # 方式一、传数字 # book_obj.authors.add(1) # 这句话的意思是给书籍绑定一个主键为1的作者 # book_obj.authors.add(2,3) # 方式二:传对象 # author_obj = models.Author.objects.get(pk=1) # author_obj1 = models.Author.objects.get(pk=3) # book_obj.authors.add(author_obj, author_obj1) ''' add 专门给第三张表添加数据 括号内可以传数字也可以传对象 并且支持传多个 ''' # 2 移除书籍与作者的绑定关系 remove # book_obj = models.Book.objects.filter(pk=1).first() # book_obj.authors.remove(2) # book_obj.authors.remove(1,3) # author_obj = models.Author.objects.get(pk=2) # author_obj1 = models.Author.objects.get(pk=3) # book_obj.authors.remove(author_obj) # book_obj.authors.remove(author_obj,author_obj1) """ remove专门给第三张关系表移除数据 括号内即可以传数字也可以传对象 并且都支持传多个 """ # 3 修改书籍与作者之间的关系 set # book_obj = models.Book.objects.filter(pk=1).first() # # # book_obj.authors.set((3,)) # # book_obj.authors.set((2, 3)) # 可以支持传多个参数 # # # 可以传对象 # author_obj = models.Author.objects.get(pk=2) # author_obj1 = models.Author.objects.get(pk=3) # # book_obj.authors.set((author_obj,)) # book_obj.authors.set([author_obj,author_obj1]) """ set 修改书籍与作者的关系 括号内支持传数字和对象 但是需要是可迭代对象 """ # 4、清空书籍与作者的关系 clear book_obj = models.Book.objects.filter(pk=1).first() book_obj.authors.clear() # 去第三张表中清空书籍为1的所有数据 """ clear() 清空关系 不需要任何的参数 """
六、跨表查询以及正向反向
1、回顾跨表查询
跨表查询的方式 1.子查询 将一张表的查询结果当做另外一张表的查询条件 正常解决问题的思路 分步操作 2.链表查询 inner join left join right join union 建议:在写sql语句或者orm语句的时候 千万不要想着一次性将语句写完 一定要写一点查一点再写一点
2、正反向的概念
正向 跨表查询的时候 外键字段是否在当前数据对象中 如果在 查询另外一张关系表 叫正向 反向 如果不在叫反向 口诀 正向查询按外键字段 反向查询按表名小写(或者有些时候在表名后面加上_set.all()) """
七、基于对象的跨表查询(子查询)
# 1.查询书籍pk为1的出版社名称 # 先拿到书籍对象 # book_obj = models.Book.objects.filter(pk=1).first() # 正向查询按字段(字段即为绑定的外键) # print(book_obj.publish) # Publish object # print(book_obj.publish.name) #西方出版社 # print(book_obj.publish.addr) #西京 # 2.查询书籍pk为2的所有作者的姓名 # 先拿到书籍对象 # book_obj = models.Book.objects.filter(pk=2).first() # 书查作者 正向 # print(book_obj.authors) #app01.Author.None # print(book_obj.authors.all()) # author_list = book_obj.authors.all() # for author_obj in author_list: # print(author_obj.name) # 3.查询作者pk为1的电话号码 # author_obj = models.Author.objects.filter(pk=1).first() # print(author_obj.author_detail) #AuthorDetail object # print(author_obj.author_detail.phone) # print(author_obj.author_detail.addr) """ 正向查询的时候 当外键字段对应的数据可以有多个的时候需要加.all() 否则点外键字典即可获取到对应的数据对象 """ # 4.查询出版社名称为东方出版社出版过的书籍 # publish_obj = models.Publish.objects.filter(name='东方出版社').first() # 出版社到书反向 # print(publish_obj.book_set) #app01.Book.None # print(publish_obj.book_set.all()) # 5.查询作者为jason写过的书 # author_obj = models.Author.objects.filter(name='jason').first() # print(author_obj.book_set) #app01.Book.None # print(author_obj.book_set.all()) # 6.查询手机号为120的作者姓名 # author_detail_obj = models.AuthorDetail.objects.filter(phone=120).first() # # print(author_detail_obj.author) # Author object # print(author_detail_obj.author.name) # print(author_detail_obj.author.age) ''' 基于对象的反向查询 表名小写是否需要加_set.all() 一对一不需要加 一对多和多对多的时候需要加 '''
八、基于双下划线跨表查询(链表查询)
# 1.查询书籍pk为1的出版社名称 # # 正向 # res = models.Book.objects.filter(pk=1).values('publish__name') # 写外键字段就意味着你已经在外键字段关联的那张表中 # print(res) #<QuerySet [{'publish__name': '西方出版社'}]> # 反向 # # res = models.Publish.objects.filter(book__pk=1) # 拿出版过pk为1的书籍对应的出版社 # res = models.Publish.objects.filter(book__pk=1).values('name') # print(res) # 2.查询书籍pk为1的作者姓名和年龄 # 正向 # res = models.Book.objects.filter(pk=1).values('title', 'authors__name', 'authors__age') # print(res) # 反向 # # res = models.Author.objects.filter(book__pk=1) # 拿出出版过书籍pk为1的作者 # res = models.Author.objects.filter(book__pk=1).values('name', 'age', 'book__title') # print(res) # 3.查询作者是jason的年龄和手机号 # # 正向 # res = models.Author.objects.filter(name='jason').values('author_detail__phone','age') # print(res) # # 反向 # res = models.AuthorDetail.objects.filter(author__name='jason').values('phone', 'author__age') # print(res) # 查询书籍pk为的1的作者的手机号 # 正向 # res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone') # print(res) # 反向 # res = models.AuthorDetail.objects.filter(author__book__pk=1).values('phone') # print(res) ''' 只要表之间有关系 你就可以通过正向的外键字段或者反向的表名小写 连续跨表操作 '''
九、聚合查询
from django.db.models import Max, Min, Avg, Count, Sum # 聚合函数需要你自己先导入 ''' 聚合查询关键字: aggregate ''' #查询所有书的平均价格 res = models.Book.objects.aggregate(avg_num=Avg('price')) # 需要自己起一个别名 print(res) #查询价格最贵的书 res = models.Book.objects.aggregate(max_num=Max('price')) print(res) #全部使用一遍 res = models.Book.objects.aggregate(Avg("price"), Max("price"), Min("price"),Count("pk"),Sum('price')) print(res)
十、分组查询
''' 分组查询关键字: annotate ''' # 1.统计每一本书的作者个数 # res = models.Book.objects.annotate(author_num=Count('authors')).values('title','author_num') # print(res) # 2.统计出每个出版社卖的最便宜的书的价格 # res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price','book__title') # print(res) # 3.统计不止一个作者的图书 # res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title') # print(res) # 4.查询各个作者出的书的总价格 # res = models.Author.objects.annotate(price_sum=Sum('book__price')).values('name','price_sum') # print(res) # 5.如何按照表中的某一个指定字段分组 """ res = models.Book.objects.values('price').annotate() 就是以价格分组 """
十一、F与Q查询
from django.db.models import F,Q # # 1.查询库存数大于卖出数的书籍 # res = models.Book.objects.filter(kucun__gt=F('maichu')) # print(res) # 2.将所有书的价格提高100 res = models.Book.objects.update(price=F('price') + 100) """ 帮你获取到表中某个字段对应的值 """ # Q能够改变查询的条件关系 and or not # 1、查询数电名字是python入门或者价格是1000的书籍 # res = models.Book.objects.filter(title='python入门', price=1000) # 这种方法实现不了 # res = models.Book.objects.filter(Q(title='python入门'), Q(price=1000)) # 逗号是and关系 # res = models.Book.objects.filter(Q(title='python入门')|Q(price=1000)) # |是or关系 # res = models.Book.objects.filter(~Q(title='python入门')|Q(price=1000)) # ~是not关系 # # print(res.query) # Q的高阶用法 # 想要实现类似以以下的功能,就必须要使用Q的高阶用法 # res = models.Book.objects.filter(('title'='python入门')) q = Q() q.connector = 'or' # q对象默认的也是and关系 这句话将下面的添加的两行变成or关系 q.children.append(('title', 'python入门')) q.children.append(('price', 1000)) res = models.Book.objects.filter(q) print(res)
Only you can control your future
You're not alone. You still have family,peopel who care for you and want to save you.
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步