django模型层 、 ORM查询
模型层 ORM查询
单表查询
前期准备工作需求:
如何只单独测试django中的某一个py文件 如何书写测试脚本
如何使用:
在任意一个py文件中书写以下代码 应用下的tests 或者自己新建一个
import os if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day53.settings") import django django.setup()
前期准备工作图片分析:
第一步:先到 settings.py配置信息:
第二步:modles 中设置数据信息
auto_now:每次修改数据的时候 都会自动将最新的更新时间记录下来auto_now_add:只在创建数据的时候将创建时间自动记录下来 之后不会自动改变
第三步: 从mange中获取四句信息,复制到相应的文件中(tests中 看你自己)在进行导入相关文件(不到入回报错)
必知必会16条
""" 必知必会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.reverse() 16.distinct() """
1.create()
""" 1.create() 返回值就是当前被创建数据的对象本身 # 日期可以手动给 models.Movie.objects.create(title='盲僧',price=4800,publish_time='2016-1-1') # 还可以直接传日期对象 from datetime import date ctime = date.today() models.Movie.objects.create(title='寒冰', price=500, publish_time=ctime) """
效果:
2.all() queryset对象
2.all() queryset对象 res = models.Movie.objects.all() print(res)
效果:
3.filter() queryset对象
res = models.Movie.objects.filter(id=1) res = models.Movie.objects.filter(pk=1) # pk指代的就是当前表的主键字段名 自动查找非常方便 res = models.Movie.objects.filter(pk=1,title='python入门') # 括号内可以放多个条件默认是AND关系
效果:
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) res = models.Movie.objects.filter(pk=1000) print(res)
效果:
res = models.Movie.objects.get(pk=1) print(res) print(res.title) print(res.price)
res = models.Movie.objects.get(pk=1000)#当查询条件不存在的时候直接报错 res = models.Movie.objects.filter(pk=1000)#为空 print(res)
效果:
5.values() QuerySet对象 [{},{},{}] 获取指定字段对的数据
# 5.values() QuerySet对象 [{},{},{}] 获取指定字段对的数据 res = models.Movie.objects.values('title','publish_time') print(res) print(res.query)
效果:
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.last() print(res)
效果:
9.update() 更新数据
# 9.update() 更新数据 返回值是受影响的行数 res = models.Movie.objects.filter(pk=2).update(title='皇子') res = models.Movie.objects.filter(pk=1).update(title='金瓶美2',price=666) print(res)
效果:
res = models.Movie.objects.filter(pk=2).update(title='皇子') print(res)
res = models.Movie.objects.filter(pk=1).update(title='蛮子',price=4300) print(res)
10.delete() 删除数据
# 10.delete() 删除数据 返回值(1, {'app01.Movie': 1}) 受影响的表及行数 res = models.Movie.objects.filter(pk=3).delete() print(res)
效果:
11.count() 统计数据条数
11.count() 统计数据条数 res = models.Movie.objects.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)
效果:
升序:
res = models.Movie.objects.order_by('price') # 默认是升序 print(res)
降序:由高到底
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('price').reverse() print(res)
效果:
16.distinct() 去重:
16.distinct() 去重:去重的前提 必须是由完全一样的数据的才可以 res =models.Movie.objects.values('title','price').distinct() print(res)
效果:
神奇的双下划线查询
1.查询价格大于200的电影
# 1.查询价格大于200的电影 res = models.Movie.objects.filter(price__gt=200) print(res)
效果:下表都大于200
2.查询价格小于1000的电影
# 2.查询价格小于1000的电影 res = models.Movie.objects.filter(price__lt=1000) print(res)
效果:
3.查询价格大于等于876.23的电影
# 3.查询价格大于等于4500的电影 res = models.Movie.objects.filter(price__gte=4500) print(res.query)
效果:
4.查询价格小于等于876.23的电影
res = models.Movie.objects.filter(price__lte=500) print(res)
效果:
5.查询价格是500 或5000 或4300
# 5.查询价格是500 或5000 或4300 res = models.Movie.objects.filter(price__in=[500,5000,4300]) print(res)
效果:
6.查询价格在4000到6000之间的电影 顾头也顾尾
# 6.查询价格在4000到6000之间的电影 顾头也顾尾 res = models.Movie.objects.filter(price__range=(4000,6000)) print(res)
效果:
7.查询电影名中包含字母p的电影
""" 模糊查询: 关键字 like 关键符号 % _ """ # 7.查询电影名中包含字母p的电影 res = models.Movie.objects.filter(title__contains='p') # 默认是区分大小写 res = models.Movie.objects.filter(title__icontains='p') # i忽略大小写 print(res)
效果:
默认是区分大小写
忽略大小写
8.查询2016年出版的电影
# 8.查询2016年出版的电影 res = models.Movie.objects.filter(publish_time__year=2016) print(res)
效果:
9.查询是1月份出版的电影
res = models.Movie.objects.filter(publish_time__month=1) print(res)
效果:
多表查询
1.图书管理系统表创建
一对多和一对一字段 外键字段会自动在后面加_id后缀
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() #年月日 时分秒 def __str__(self): return self.title 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) # 该字段新增数据自动添加 无需考虑 # 出版社 一对多 外键字段建在多的一方 publish = models.ForeignKey(to='Publish') # 作者 多对多 外键字段建在任意一方均可 推荐你建在查询频率较高的表 authors = models.ManyToManyField(to='Author') # 库存数 kucun = models.BigIntegerField(default=1000) # 卖出数 maichu = models.BigIntegerField(default=1000) 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)
2.外键字段的增删改查
一对多 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='金瓶美',price=66.66,publish=publish_obj)
效果:
查:
改
# 改1 models.Book.objects.filter(pk=1).update(publish_id=3) 2. publish_obj = models.Publish.objects.get(pk=4) models.Book.objects.filter(pk=1).update(publish=publish_obj)
效果:
删
# 删 """ 外键字段在1.X版本中默认就是级联更新级联删除的 2.X版本中 则需要你自己手动指定 百度一大堆 """
多对多
1 给书籍绑定作者关系 add
""" add专门给第三张关系表添加数据 括号内即可以传数字也可以传对象 并且都支持传多个 """
代码:
# 多对多 # 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) 2. # author_obj = models.Author.objects.get(pk=1) # author_obj1 = models.Author.objects.get(pk=3) # book_obj.authors.add(author_obj) # book_obj.authors.add(author_obj,author_obj1) """ add专门给第三张关系表添加数据 括号内即可以传数字也可以传对象 并且都支持传多个 """
效果:
# book_obj = models.Book.objects.filter(pk=1).first() # 书籍和作者的关系是由第三张表绝对 也就意味着你需要操作第三张表 # print(book_obj.authors) # 书籍对象点虚拟字段authors就类似于已经跨到书籍和作者的第三张关系表中
2 移除书籍与作者的绑定关系 remove
""" remove专门给第三张关系表移除数据 括号内即可以传数字也可以传对象 并且都支持传多个 """
# 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专门给第三张关系表移除数据 括号内即可以传数字也可以传对象 并且都支持传多个 """
效果:
# book_obj = models.Book.objects.filter(pk=1).first() # book_obj.authors.remove(2)
# book_obj = models.Book.objects.filter(pk=1).first() # 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)
3 修改书籍与作者的关系 set
""" set 修改书籍与作者的关系 括号内支持传数字和对象 但是需要是可迭代对象 """
# 3 修改书籍与作者的关系 set 1. book_obj = models.Book.objects.filter(pk=1).first() book_obj.authors.set((3,)) book_obj.authors.set((2,3)) 2. 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() 清空关系 不需要任何的参数 """
# 4 清空书籍与作者关系 # book_obj = models.Book.objects.filter(pk=1).first() # book_obj.authors.clear() # 去第三张表中清空书籍为1的所有数据 """ clear() 清空关系 不需要任何的参数 """
效果:
3.跨表查询
跨表查询的方式
1.子查询
1.子查询 将一张表的查询结果当做另外一张表的查询条件 正常解决问题的思路 分步操作
2.链表查询
2.链表查询 inner join left join right join union
建议
建议:在写sql语句或者orm语句的时候 千万不要想着一次性将语句写完 一定要写一点查一点再写一点
正反向的概念
正向
跨表查询的时候 外键字段是否在当前数据对象中 如果在 查询另外一张关系表 叫正向
反向
如果不在叫反向
口诀
口诀: 正向查询按外键字段 反向查询按表名小写 _set
1.基于对象的跨表查询(子查询)
""" 正向查询的时候 当外键字段对应的数据可以有多个的时候需要加.all() 否则点外键字典即可获取到对应的数据对象 """
1.查询书籍pk为1的出版社名称
# 基于对象的跨表查询(子查询) 1.查询书籍pk为1的出版社名称 book_obj = models.Book.objects.filter(pk=1).first() print(book_obj.publish) print(book_obj.publish.name) print(book_obj.publish.addr)
效果:
2.查询书籍pk为1的所有作者的姓名
# 2.查询书籍pk为1的所有作者的姓名 book_obj = models.Book.objects.filter(pk=1).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的电话号码
# 3.查询作者pk为1的电话号码 author_obj = models.Author.objects.filter(pk=1).first() print(author_obj.author_detail) print(author_obj.author_detail.phone) print(author_obj.author_detail.addr)
效果:
""" 正向查询的时候 当外键字段对应的数据可以有多个的时候需要加.all() 否则点外键字典即可获取到对应的数据对象 """
4.查询出版社名称为东方出版社出版过的书籍
# 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写过的书
# 5.查询作者为孙尚香写过的书 author_obj = models.Author.objects.filter(name='孙尚香').first() print(author_obj.book_set) # app01.Book.None print(author_obj.book_set.all())
效果:
6.查询手机号为180的作者姓名
# 6.查询手机号为180的作者姓名 author_detail_obj = models.AuthorDetail.objects.filter(phone=180).first() print(author_detail_obj.author) print(author_detail_obj.author.name) print(author_detail_obj.author.age)
效果:
2.基于双下划线的跨表查询
""" 基于对象的反向查询 表名小写是否需要加_set.all() 一对多和多对多的时候需要加 一对一不需要 """
1.查询书籍pk为1的出版社名称
正向
# 正向 res = models.Book.objects.filter(pk=1).values('publish__name') # 写外键字段 就意味着你已经在外键字段管理的那张表中 print(res)
效果:
反向
# 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的作者 res1 = models.Author.objects.filter(book__pk=1).values('name','age','book__title') print(res) print(res1)
效果:
3.查询作者是jason的年龄和手机号
正向
# 正向 res=models.Author.objects.filter(name='jason').values('age','author_detail__phone') # print(res)
效果:
反向
res = models.AuthorDetail.objects.filter(author__name='孙尚香') # 拿到jason的个人详情 res1 = models.AuthorDetail.objects.filter(author__name='孙尚香').values('phone','author__age') print(res) print(res1)
效果:
查询书籍pk为的1的作者的手机号
""" 只要表之间有关系 你就可以通过正向的外键字段或者反向的表名小写 连续跨表操作 """
# 查询书籍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
查询所有书的平均价格
# 查询所有书的平均价格 from django.db.models import Max, Min, Avg, Count, Sum res = models.Book.objects.aggregate(avg_num=Avg('price')) print(res)
效果:
查询价格最贵的书
from django.db.models import Max, Min, Avg, Count, Sum # 查询价格最贵的书 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
from django.db.models import Max, Min, Avg, Count, Sum # 1.统计每一本书的作者个数 res = models.Book.objects.annotate(author_num=Count('authors')).values('title','author_num') print(res)
1.统计每一本书的作者个数
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.查询库存数大于卖出数的书籍
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的书籍
# 1.查询书的名字是python入门或者价格是1000的书籍 res = models.Book.objects.filter(title='python入门',price=1000) # and关系 res1 = models.Book.objects.filter(Q(title='python入门'),Q(price=1000)) # 逗号是and关系 res2 = models.Book.objects.filter(Q(title='python入门')|Q(price=1000)) # |是or关系 res3 = models.Book.objects.filter(~Q(title='python入门')|Q(price=1000)) # ~是not关系 print(res.query) print(res1.query) print(res2.query) print(res3.query)
效果:
Q的高阶用法
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)
效果: