Django–模型层orm查询
文章目录
Django–模型层orm查询
首先,在django项目中单独测试django中的某一个py文件,需要写入脚本。
在需要测试的py文件中或自己创建的新py文件中书写以下代码(或在manage.py文件下粘贴)
import os
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day53.settings")
import django
django.setup()
**********导入的模块或测试需要在此处开始写*********
一、单表查询(增、删、改、查)
基本查询
演示之前需要先创建以下表格
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() # 年月日
"""
auto_now:每次修改数据的时候 都会自动将最新的更新时间记录下来
auto_now_add:只在创建数据的时候将创建时间自动记录下来 之后不会自动改变
"""
# 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)
只要是queryset对象 就可以通过 点query 的方式查看到获取到当前对象内部sql语句,print(res.query)
-
create()
create() 创建、新增 #返回值就是当前被创建数据的对象本身 #日期可以手动给 models.Movie.objects.create(title='3D肉蒲团s',price=999.23,publish_time='2016-1-1') #还可以直接传日期对象 from datetime import date ctime = date.today() models.Movie.objects.create(title='西游记', price=666.23, publish_time=ctime) #ORM创建数据只需要执行此py文件就行了。
-
all()
all() #查所有,当某个对象有多条数据时,返回结果会显示none,此时就需要用到all查询才会显示所有数据 res = models.Movie.objects.all() #res.queryset对象查看SQL语句 print(res)
-
filter()
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关系 # 只要是queryset对象 就可以通过 点query 的方式查看到获取到当前对象内部sql语句 print(res.query)
-
update()
update() #更新数据 返回值是受影响的行数 res = models.Movie.objects.filter(pk=1).update(title='金瓶梅2') res = models.Movie.objects.filter(pk=1).update(title='金瓶梅2',price=666) print(res)
-
delete()
delete() #删除数据 返回值(1, {'app01.Movie': 1}) 1代表受影响的表及行数 res = models.Movie.objects.filter(pk=3).delete() print(res)
-
first()
first() #数据对象 取第一个元素对象 res = models.Movie.objects.filter().first() print(res)
-
last()
last() #数据对象 取最后一个元素对象 res = models.Movie.objects.last() print(res)
-
get()
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)
-
values()
values() #QuerySet对象 [{},{},{}] 获取指定字段对的数据 res = models.Movie.objects.values('title','publish_time') print(res) print(res.query)
-
values_list()
values_list() #QuerySet对象 [(),(),()] 获取指定字段对的数据 res = models.Movie.objects.values_list('title','price') print(res)
-
order_by()
order_by #按照指定字段排序 res = models.Movie.objects.order_by('price') # 默认是升序 res = models.Movie.objects.order_by('-price') # 减号就是降序 print(res)
-
count()
count() #统计数据条数 res = models.Movie.objects.count() print(res)
-
exclude()
exclude() #排除什么什么之外 少选条件 res = models.Movie.objects.exclude(pk=1) print(res)
-
exists()
exists() #返回的是布尔值 判断前面的对象是否有数据 了解即可 res = models.Movie.objects.filter(pk=1000).exists() print(res)
-
reverse()
reverse() #反转 res = models.Movie.objects.order_by('price').reverse() print(res)
-
distinct()
distinct() #去重:去重的前提 必须是由完全一样的数据的才可以(id是唯一的,可将条件换为名字、价格等) res = models.Movie.objects.values('title','price').distinct() print(res)
下划线查询
-
__gt、大于
#查询价格大于200的电影 res = models.Movie.objects.filter(price__gt=200) print(res)
-
__lt、小于
#查询价格小于500的电影 res = models.Movie.objects.filter(price__lt=500) print(res)
-
__gte、大于等于
#查询价格大于等于876.23的电影 #python里面小数是不精准的876.23后面会多出小数,所以876.23是查不到的,解决方法可以转换成字符串来比较大小 res = models.Movie.objects.filter(price__gte=876.23) print(res.query)
-
__lte、小于等于
#查询价格小于等于500的电影 res = models.Movie.objects.filter(price__lte=500) print(res)
-
__in、在条件中的
#查询价格是123 或666 或876 res = models.Movie.objects.filter(price__in=[123,666,876]) print(res)
-
__range、区间
#查询价格在200到900之间的电影 顾头也顾尾 res = models.Movie.objects.filter(price__range=(200,900)) print(res)
-
__contains、模糊查询
# 查询电影名中包含字母p的电影 """ python模糊查询: 关键字 like 关键符号 _ % """ res = models.Movie.objects.filter(title__contains='p') # 默认是区分大小写 res = models.Movie.objects.filter(title__icontains='p') # i忽略大小写 print(res)
-
_time__year、时间–年
#查询2014年出版的电影 res = models.Movie.objects.filter(publish_time__year=2014) print(res)
-
_time__month、时间–月
#查询是1月份出版的电影 res = models.Movie.objects.filter(publish_time__month=1) print(res)
二、外键字段(增、删、改、查)
一对多
-
增
#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.X版本中默认就是级联更新级联删除的 2.X版本中 则需要你自己手动指定 百度一大堆
-
改
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)
-
查
使用单表查询的方式即可
多对多
-
add、增
#给书籍绑定作者关系 add 1. 直接通过条件 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专门给第三张关系表添加数据 括号内即可以传数字也可以传对象 并且都支持传多个 """
-
remove、删
#移除书籍与作者的绑定关系 remove 1. 通过条件 book_obj = models.Book.objects.filter(pk=1).first() book_obj.authors.remove(2) book_obj.authors.remove(1,3) 2.通过对象 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专门给第三张关系表移除数据 括号内即可以传数字也可以传对象 并且都支持传多个 """ # clear() # 清空书籍与作者关系 # book_obj = models.Book.objects.filter(pk=1).first() # book_obj.authors.clear() # 去第三张表中清空书籍为1的所有数据 """ clear() 清空关系 不需要任何的参数 """
-
set、改
#修改书籍与作者的关系 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 修改书籍与作者的关系 括号内支持传数字和对象 但是需要是可迭代对象 """
三、多表查询
多表查询的方式
-
子查询,将一张表的查询结果当作另一张表的查询条件
-
链表查询
inner join left join right join union
建议:在写SQL语句或者ORM语句的时候,千万不要想着一次性写完,一定要写一点查一点再写一点。
正反向的概念
正向:
跨表查询得时候,外键字段是否在当前数据对象中,如果在,查询另外一张表关系,叫正向
反向:
如果正向描述不在,就叫反向
口诀:
正向查询按外键字段,反向查询按表名小写
基于对象的跨表查询(子查询)
-
查询书籍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)
-
查询书籍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)
-
查询作者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(),否则点外键字典即可获取到对应的数据对象
-
查询出版社名称为东方出版社出版过的书籍
publish_obj = models.Publish.objects.filter(name='东方出版社').first() print(publish_obj.book_set) # app01.Book.None print(publish_obj.book_set.all())
-
查询作者为Jason写过的书籍
author_obj = models.Author.objects.filter(name='jason').first() print(author_obj.book_set) # app01.Book.None print(author_obj.book_set.all())
-
查询手机号为120的作者的姓名
author_detail_obj = models.AuthorDetail.objects.filter(phone=120).first() print(author_detail_obj.author) print(author_detail_obj.author.name) print(author_detail_obj.author.age)
基于双下划线查询
-
查询书籍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)
-
查询书籍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)
-
查询作者是jason的年龄和手机号
正向 res = models.Author.objects.filter(name='jason').values('age','author_detail__phone') print(res) 反向 res = models.AuthorDetail.objects.filter(author__name='jason') # 拿到jason的个人详情 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
# 查询所有书的平均价格
# 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)
五、分组查询
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查询
F查询——专门取对象中某列值的操作
Q查询——能够改变查询的条件关系 and or not
1.查询书的名字是python入门或者价格是1000的书籍
res = models.Book.objects.filter(title='python入门',price=1000) # and关系
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 = 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)