ORM查询操作
1、如何只单独测试Django中的某一个py文件
在应用下的tests文件或者新建任意一个py文件中书写以下代码:
# 在manage.py文件中复制过来 import os if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mypoject.settings") #手写导入django模块 import django django.setup()
2、单表查询之必知必会16条
1、create()
给表添加数据,返回值就是当前被创建数据的对象本身
from app01 import models res = models.Movie.objects.create(title='西游记', price=999.99) print(res) # Movie object
2、all()
查询表中所有的数据,返回值是queryset对象,并且,只要返回值是queryset对象就可以使用对象 点query 的方式查看获取到的内部SQL语句
res = models.Movie.objects.all() print(res) # <QuerySet [<Movie: Movie object>, <Movie: Movie object>]> print(res.query) # SELECT `app01_movie`.`id`, `app01_movie`.`title`, `app01_movie`.`price`, `app01_movie`.`publish_time` FROM `app01_movie`
3、filter()
不传参数就是查询所有,传参数就是查询指定的数据,返回值是列表套queryset对象,当查询对象不存在时,不会报错
pk 就是指当前的主键字段名
res = models.Movie.objects.filter() # 不传参数就是查所有对象 print(res) # <QuerySet [<Movie: Movie object>, <Movie: Movie object>]> # pk 就是指当前的主键字段名 res1 = models.Movie.objects.filter(pk=1, title='西游记') # 可以传多个参数是以and连接 print(res1) # <QuerySet [<Movie: Movie object>]>
4、update()
更新数据,先查出数据再更新,返回值是受影响的行数
res = models.Movie.objects.filter(pk=1).update(title='水浒传') print(res) # 1
5、delete()
删除数据,先查出要删除的数据,再删除,返回值是受影响的表和行数 (1, {'app01.Movie': 1})
res = models.Movie.objects.filter(pk=3).delete() print(res) # (1, {'app01.Movie': 1})
6、first()
先获取到数据对象,取第一个元素
res = models.Movie.objects.filter().first() print(res) # Movie object print(res.title) # 西游记 # 因为通过主键只获取到一条数据,所有查第一个就是pk=1的数据 res = models.Movie.objects.filter(pk=1).first() print(res) # Movie object print(res.title) # 西游记
7、last()
先获取到数据对象,取最后一个元素
res = models.Movie.objects.filter().last() print(res) # Movie object print(res.title, res.price) # 东游记 888.88 # 因为通过主键只获取到一条数据,所有查最后一个就是pk=1的数据 res = models.Movie.objects.filter(pk=1).last() print(res) # Movie object print(res.title, res.price) # 西游记 999.99
8、get()
返回值是直接获取对象本身,当查询条件不存在时会报错,并且必须要传一个参数,不推荐使用
res = models.Movie.objects.get(pk=1) print(res)
9、values()
获取queryset对象是 [{},{}] 不传参数就是获取所有,传参数可以指定获取对应的字段数据
res = models.Movie.objects.values() print(res) # <QuerySet [{'id': 1, 'title': '西游记', 'price': Decimal('999.99'), 'publish_time': datetime.date(2014, 1, 8)}, {'id': 2, 'title': '东游记', 'price': Decimal('888.88'), 'publish_time': datetime.date(2011, 1, 8)}]> res = models.Movie.objects.values('title', 'price') print(res) # <QuerySet [{'title': '西游记', 'price': Decimal('999.99')}, {'title': '东游记', 'price': Decimal('888.88')}]>
10、values_list()
获取queryset对象是 [(,)(,)] 不传参数就是获取所有,传参数可以指定获取对应的字段数据
res = models.Movie.objects.values_list() print(res) res = models.Movie.objects.values_list('title') print(res) # <QuerySet [('西游记',), ('东游记',)]>
11、order_by()
按照指定字段进行排序,返回queryset对象,对数据库不进行修改
# 默认升序 res = models.Movie.objects.order_by('price') print(res) # 减号就是降序 res = models.Movie.objects.order_by('-price') print(res)
12、count()
统计数据总共有多少条,不能指定参数统计
res = models.Movie.objects.count() print(res) # 2
13、exclude()
排除什么之外,返回值是排除之外的所有数据
res = models.Movie.objects.exclude(pk=1) # 排除主键是1之外的数据 print(res)
14、exists()
返回值是布尔值,判断当前对象是否有数据,返回值是布尔值
res = models.Movie.objects.filter(pk=21).exists() print(res) # False
15、reverse()
反转数据,将原排序后的数据反转
res = models.Movie.objects.order_by('price').reverse() print(res)
16、distinct()
去重,去重的前提是必须要有两个数据完全一样才可以,一般有主键,都不会完全一样的
res = models.Movie.objects.values('title').distinct() # 由于有主键,不完全一样,所有不会去重 print(res)
3、单表查询之神奇的下划线查询
1、查询价格大于200的电影:price__gt 大于 gt
# 1.查询价格大于200的电影 res = models.Movie.objects.filter(price__gt=200) print(res)
2、查询价格小于900的电影 : price__lt 小于 lt
res = models.Movie.objects.filter(price__lt=900) print(res)
3、查询价格大于等于888.88的电影:price__gte 大于等于 gte
res = models.Movie.objects.filter(price__gte=888.88) print(res)
4、查询价格小于等于999.99的电影:price__lte 小于等于 lte
由于python对小数不是很敏感,所有小数有可能会不会精确找到,最好定义用整数
res = models.Movie.objects.filter(price__lte=999.99) print(res)
5、查询价格是888或999的数据:price__in=[888,999] 注意是列表
由于正常用filter查询多个时是and关系,所以可以使用双下划线的方式
res = models.Movie.objects.filter(price__in=[888,999]) print(res)
6、查询价格在800到900之间 电影数据,顾头也顾尾 price__range=(800,900),注意是小括号
res = models.Movie.objects.filter(price__range=(800,900)) print(res)
7、查询电影名中包含字母L的电影
__contains 是区分大小写的
__icontains 是不区分大小写的
res = models.Movie.objects.filter(title__contains='l') print(res) # <QuerySet [<Movie: 东游记l>]> res = models.Movie.objects.filter(title__icontains='l') print(res) # <QuerySet [<Movie: 东游记L>, <Movie: 东游记l>]>
8、查询2014年、月、日出版的电影 __ year __ day __ month
res = models.Movie.objects.filter(publish_time__year=2014) print(res) res = models.Movie.objects.filter(publish_time__month=1) print(res) res = models.Movie.objects.filter(publish_time__day=8) print(res)
4、多表查询之外键字段的增删改查
1、一对多
# 增:方法一:直接写实际的字段publish_id models.Book.objects.create(name='红楼梦', price=888, store=500, sell=800, publish_id = 3) # publish_id真实表中的的字段 # 增:方法二:先get方法拿到出版社对象,再给书加对应的出版社 publish_obj = models.Publish.objects.get(pk=2) models.Book.objects.create(name='三体', price=888, store=600, sell=800, publish = publish_obj) # publish自定义时的字段 # 改:1.直接指名道姓的修改 models.Book.objects.filter(pk=9).update(publish_id=3) publish_obj = models.Publish.objects.get(pk=1) models.Book.objects.filter(pk=9).update(publish=publish_obj) # 删除:外键字段在1.x版本默认就是级联更新级联删除,2.x版本需要手动指定
2、多对多
1、绑定关系:add
add专门给第三张表添加数据,括号内既可以传数字也可以传对象,并且支持传多个
# 多对多 #给书籍绑定作者关系 # 方式一: # 1.拿到书对象 book_obj = models.Book.objects.filter(pk=3).first() # 2.书籍对象点虚拟字段authors就跳到第三张表中了,再add绑定 book_obj.authors.add(1) book_obj.authors.add(2,3) # 可以支持一本书绑定多个作者 # 方式二 # 1.拿到书籍对象 book_obj = models.Book.objects.filter(pk=5).first() # 2.通过get方法拿到作者对象 author_obj = models.Author.objects.get(pk=1) # 3.给书籍对象点虚拟的authors跳转到第三张表,add对象添加数据 book_obj.authors.add(author_obj)
2、移除关系:remove
remove专门给第三张表移除数据,括号内即可以传数字也可以传对象,并且都支持多个
# 方式一: # 1.拿到书对象 book_obj = models.Book.objects.filter(pk=3).first() # 2.书籍对象点虚拟字段authors就跳到第三张表中了,再remove移除关系 book_obj.authors.remove(1) book_obj.authors.remove(2,3) # 可以支持一本书传多个参数移除关系 # 方式二 # 1.拿到书籍对象 book_obj = models.Book.objects.filter(pk=5).first() # 2.通过get方法拿到作者对象 author_obj = models.Author.objects.get(pk=1) # 3.给书籍对象点虚拟的authors跳转到第三张表,remove移除关系 book_obj.authors.remove(author_obj)
3、修改关系:set
修改两张表的关系,括号内支持传数字和对象,但是需要是可迭代对象,可以set中是元组或者列表
# 方式一: # 1.拿到书对象 book_obj = models.Book.objects.filter(pk=3).first() # 2.书籍对象点虚拟字段authors就跳到第三张表中了,再set设置关系 book_obj.authors.set((3,)) book_obj.authors.set((1,3)) # 可以支持一本书传多个参数设置关系 # 方式二 # 1.拿到书籍对象 book_obj = models.Book.objects.filter(pk=5).first() # 2.通过get方法拿到作者对象 author_obj = models.Author.objects.get(pk=1) # 3.给书籍对象点虚拟的authors跳转到第三张表,set设置关系 book_obj.authors.set([author_obj])
4、清空关系:clear
清空第三张表的数据,不需要传任意参数
# 清空第三表中书的id是5的数据 book_obj = models.Book.objects.filter(pk=5).first() book_obj.authors.clear()
5、多表查询之跨表查询
跨表查询的方式:子查询和链表查询
正向和反向的概念:
正向:跨表查询的时候 外键字段是否在当前数据对象中,如果在查询另一张表关系,叫做正向
反向:如果外键字段不在当前的数据对象中,叫做反向
口诀:正向查询按外键字段如果有多个对应加.all(),反向查询按表名小写,如果有多个对应加_set.all()
1、基于对象的跨表查询(子查询)
将一张表的查询结果当做另外一张表的查询条件,分布操作
# 1.查询书籍pk为5的出版社名称 正向按照外键字段 book_obj = models.Book.objects.filter(pk=5).first() print(book_obj.publish) # Publish object print(book_obj.publish.name) # 东方出版社 print(book_obj.publish.addr) # 东京 #2. 查询书籍pk为3的作者的名字 正向按照外键字段 book_obj = models.Book.objects.filter(pk=3).first() print(book_obj.authors.all()) # 有多个的时候需要用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) # 只有一个对应就不需要用all print(author_obj.author_detail.phone) # 4.查询出版社名称为东方出版社出版的书 反向按照表名小写 publish_obj = models.Publish.objects.filter(name='东方出版社').first() print(publish_obj.book_set.all()) # 有多条对应就要用_set.all() # 5.查询作者为Jason写过的书 author_obj = models.Author.objects.filter(name='Jason').first() print(author_obj.book_set.all()) # 有多个数据时要加_set.all() # 6.查询手机号为120的作者姓名 author_detail_obj = models.AuthorDetail.objects.filter(phone=120).first() print(author_detail_obj.author) # 反向按照表名小写 print(author_detail_obj.author.name)
2、基于双下划线的跨表查询(链表查询)
只要表之间有关系,就可以通过正向的外键字段或反向的表名小写,连续跨表操作获取对应的数据
# 1.查询书籍pk为3的出版社名称 # 正向 res = models.Book.objects.filter(pk=3).values('publish__name') print(res) # 反向 # res = models.Publish.objects.filter(book__pk=3) # 拿pk为3的书对应的出版社对象 res = models.Publish.objects.filter(book__pk=3).values('name') print(res) # 2.查询书籍pk为3的作者名和年龄 # 正向 res = models.Book.objects.filter(pk=3).values('authors__name', 'authors__age','name') print(res) # 反向 # res = models.Author.objects.filter(book__pk=3) # 拿到书籍pk=3的作者对象 res = models.Author.objects.filter(book__pk=3).values('name', 'age', 'book__name') 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) # 4. 查询书籍pk为3的的作者手机号 # 正向 res = models.Book.objects.filter(pk=3).values('authors__author_detail__phone') print(res) # 反向 res = models.AuthorDetail.objects.filter(author__book__pk=3).values('phone') print(res)
6、聚合查询
1、首先需要导入聚合函数
from django.db.models import Max, Min, Avg, Count, Sum
2、关键字:aggregate
from django.db.models import Max, Min, Sum, Count, Avg # 查询所有书的平均价格 res = models.Book.objects.aggregate(avg_num=Avg('price')) # avg_num是变量名,可不用 print(res) # 查询所有书中最贵的书 res = models.Book.objects.aggregate(max_num=Max('price')) print(res) # 全部使用 res = models.Book.objects.aggregate(Min('price'), Count('pk'), Sum('price')) print(res)
7、分组查询
关键字:annotate
from django.db.models import Max, Min, Sum, Count, Avg # 1.统计每一本书的作者个数 # res = models.Book.objects.annotate(author_num=Count('authors')).values('name') res = models.Book.objects.annotate(author_num=Count('authors')) print(res) # 2.统计每个出版社卖的最贵的书 res= models.Publish.objects.annotate(max_price=Max('book__price')).values('name', 'book__name', 'book__price') print(res) # 3.统计不止一个作者的图书 res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('name') print(res) # 4.查询各个作者的书的总价格 res = models.Author.objects.annotate(price_sum=Sum('book__price')).values('name', 'price_sum') print(res)
8、F与Q查询
Q:能够改变查询的条件关系,and or not
首先需要导入F和Q模块
from django.db.models import F, Q
from django.db.models import F, Q # 1.查询所有库存小于卖出的书 res = models.Book.objects.filter(store__lt=F('sell')) print(res) # 2.将所有的书价格提高100 res = models.Book.objects.update(price=F('price')+100) # 直接对数据库进行操作 # 查询书的名字是西游记或者价格是888的书 res = models.Book.objects.filter(name='西游记', price=888) # and关系 res = models.Book.objects.filter(Q(title='西游记'),Q(price=1000)) # 逗号是and关系 res = models.Book.objects.filter(Q(title='西游记')|Q(price=1000)) # |是or关系 res = models.Book.objects.filter(~Q(title='西游记')|Q(price=1000)) # ~是not关系
# Q的高阶用法 # res = models.Book.objects.filter('title'='python入门') q = Q() q.connector = 'or' # q对象默认也是and关系 可以通过connector改变or q.children.append(('title','python入门')) q.children.append(('price',1000)) res = models.Book.objects.filter(q) print(res)