#一、ORM单表的增删改查
#表记录的添加
from app1.models import *
#方式1
Author.objexts.create(name='alvin')
#方式2
Author.objects.create(**{'name':'alex'})
#方式1
author = Author(name='alvin')
author.save()
#方式2
author = Author()
author.name = 'alvin'
author.save()
#表记录的修改
#方式1
Book.object.filter(author='kang').update(price=100)
#方式2(有save的效率低,不建议用)
b = Book.objects.get(author='kang')
b.price = 123
b.save()
#表记录的删除
Book.objects.filter(author='kang').delete()
#表记录的查找
#相关查询API
filter(**kwargs) 包含了与所给筛选条件相匹配的对象,按照条件选出结果
all() 查询所有结果
get(**kwargs) 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会报错
#下面的方法都是对查询的结果进行处理
values(*field) 返回一个字典序列
exclude(**kwargs) 包含了与所给筛选条件不匹配的对象,按照条件排除结果
order_by(*field) 对查询结果进行排序
reverse() 对查询结果反向排序
distinct() 从返回结果中剔除重复记录
values_list(*field) 返回的是一个元组序列,values返回的是一个字典序列
count() 返回数据库中匹配查询(QuerySet)的对象数量
first() 返回第一条记录
last() 返回最后一条记录
exists() 如果QuerySet包含数据,则返回True,否则返回False
__gt大于
__lt小于
__in 等于
__contains 按大写选择
__icontains 不区分大小写
__range 在什么之间
# django 升级到2.0之后,表与表之间关联的时候,必须要写on_delete参数,否则会报异常:
# TypeError: init() missing 1 required positional argument: ‘on_delete’
#
# on_delete各个参数的含义如下:
#
# on_delete=None, # 删除关联表中的数据时,当前表与其关联的field的行为
# on_delete=models.CASCADE, # 删除关联数据,与之关联也删除
# on_delete=models.DO_NOTHING, # 删除关联数据,什么也不做
# on_delete=models.PROTECT, # 删除关联数据,引发错误ProtectedError
# # models.ForeignKey('关联表', on_delete=models.SET_NULL, blank=True, null=True)
# on_delete=models.SET_NULL, # 删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空,一对一同理)
# # models.ForeignKey('关联表', on_delete=models.SET_DEFAULT, default='默认值')
# on_delete=models.SET_DEFAULT, # 删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值,一对一同理)
# on_delete=models.SET, # 删除关联数据,
# a. 与之关联的值设置为指定值,设置:models.SET(值)
# b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
#
# 由于多对多(ManyToManyField)没有 on_delete 参数,所以以上只针对外键(ForeignKey)和一对一(OneToOneField)
#二、ORM多表的增删改查
# ORM多表1(一对多)
# 添加
Book.objects.create(name='python',price=34,pub_date='2021-01-01',publish_id=2)
Book.objects.create(name='java',price=10,pub_date='2019-08-01',publish_id=3)
# 修改
Book.objects.filter(id=17).update(price=100,pub_date='1998-11-13')
# 删除
Book.objects.filter(name='php').delete() #删除名字为PHP的书
# 查询:
# 实例1:查询人民出版社出过的所有书籍的名字和价格
# 方式1
pub_obj = Publish.objects.filter(name='人民出版社')[0]
ret = Book.objects.filter(publish=pub_obj).values('name','price')
print(ret)
# 方式2
pub_obj = Publish.objects.filter(name='人民出版社')[0]
ret = pub_obj.book_set.all().values('name','price')
print(ret)
# 方式3(通过双下划线)
ret = Book.objects.filter(publish__name='人民出版社').values('name','price')
print(ret)
# 实例2:查询python这本书出版社的名字
# 方式1
ret0 = Publish.objects.filter(book__name='python').values('name')
print(ret0)
# 方式2
ret1 = Book.objects.filter(name='python').values('publish__name')
print(ret1)
# 实例3:通过对象来查找记录
book_obj = Book.objects.get(name='python')
print(book_obj) #python
print(book_obj.name) #name=python
print(book_obj.price) #price=34
print(book_obj.pub_date) #pub_date=2021-01-01
print(book_obj.publish) #Publish object
print(book_obj.publish.name) #机械出版社
print(book_obj.publish.city) #上海
print(book_obj.publish.id) #2
print(book_obj.publish_id) #publish_id=2
print(book_obj.id) #id=13
# 实例4:查询生产地在甘肃兰州的书的名字
ret = Book.objects.filter(publish__city='甘肃兰州').values('name')
print(ret) #go和java
# 实例5:查找生产时间在2010-01-01到2021-07-29之间出版的书
ret = Book.objects.filter(pub_date__lt='2021-07-29',pub_date__gt='2010-01-01').values('name') #__lt小于,__gt大于
print(ret) #python/linux/go/HTML/java
# 实例6:查找java的出版社
# 方式1
ret = Publish.objects.filter(book__name='java').values('name')
print(ret) #甘肃出版社
# 方式2
ret = Book.objects.filter(name='java').values('publish__name')
print(ret)
# ORM多表2(多对多)
#增加
# 创建多对多的关系:author = models.ManyToManyField("Author")------>此时会自动生成关联表
#(1)book_authors表添加信息
#添加一条信息
book_obj = Book.objects.get(id=13) #书的对象
author_objs = Author.objects.get(id=1)
book_obj.authors.add(author_objs)
#添加多条信息
book_obj = Book.objects.get(id=19)
author_objs = Author.objects.all()
book_obj.authors.add(*author_objs)
#(2)通过创建第三张表来添加信息
Book_Author.objects.create(book_id=16,author_id=1)
#修改
修改与一对多修改方式一样
#删除
#对book_authors表删除信息(即删除自动生成表的信息)
#删除一条信息
book_obj = Book.objects.get(id=19)
author_objs = Author.objects.get(id=1)
book_obj.authors.remove(author_objs)
#删除多条信息
book_obj = Book.objects.get(id=19)
author_objs = Author.objects.all()
book_obj.authors.remove(*author_objs)
#查询
#(一)、通过对象的方式绑定关系(自动生成的第三张表的操作)
#方式1
book_obj = Book.objects.get(id=13)
print(book_obj.authors.all()) #QuerySet对象
print(type(book_obj.authors.all())) #<class 'django.db.models.query.QuerySet'>
#方式2
author_obj = Author.objects.get(id=2)
print(author_obj.book_set.all())
#(二)、通过创建的第三张表来查找
#alex出过的书籍名称及价格
ret = Book.objects.filter(book_author__author__name='alex').values('name','price')
print(ret)
#注:以下实例都使用自动生成的第三张表来操作
#实例1:查找alex出过的书籍的名字及价格
ret_0 = Book.objects.filter(authors__name='alex').values('name','price')
print(ret_0) #<QuerySet [{'name': 'HTML', 'price': 540}, {'name': 'java', 'price': 10}, {'name': 'python', 'price': 34}]>
#聚合函数:
annotate(*args,**kwargs):可以通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值(也可以是平均值或总和),即为查询集的每一项生成聚合。
aggregate(*args,**kwargs):通过对QuerySet进行计算,返回一个聚合值的字典。aggregate()中每一个参数都指定一个包含在字典中的返回值。即在查询集上生成聚合。
#实例2:求price的平均值
ret_1 = Book.objects.all().aggregate(Avg('price'))
print(ret_1)
#实例3:求price的总和
ret_2 = Book.objects.all().aggregate(Sum('price'))
print(ret_2)
#实例4:求price的最小值
ret_3 = Book.objects.all().aggregate(Min('price'))
print(ret_3) #{'price__min': 20}
#实例5:求price的最大值
ret_4 = Book.objects.all().aggregate(max_money=Max('price'))
print(ret_4) #{'max_money': 550}------>max_mongy是可以自己定义的
#实例6:alex出过书的总价格
ret_5 = Book.objects.filter(authors__name='alex').aggregate(Sum('price'))
print(ret_5)
#实例7:alex出过书的数量
ret_6 = Book.objects.filter(authors__name='alex').aggregate(Count('name'))
print(ret_6)
#分组
#实例8:求每个作者出过书的总价格
ret_7 = Book.objects.values('authors__name').annotate(Sum('price'))
print(ret_7)
#F查询:使用查询条件的值进行操作
#实例9:为每本书增加10块钱
Book.objects.all().update(price=F('price')+10)
#Q查询:
#实例10:找价格为44或者名字为go的
ret_8 = Book.objects.filter(Q(price=44) | Q(name='go'))
print(ret)
#实例11:查找书名中有P的书
ret_9 = Book.objects.filter(Q(name__contains='p'))
print(ret_9)
#实例12:查找书名中有l的并且价格为53的书
ret_10 = Book.objects.filter(Q(name__contains='l') & Q(price=53))
print(ret_10) #linux
#~(非)的使用
ret_11 = Book.objects.filter(Q(name__contains='l')& ~ Q(price=53))
print(ret_11) #linux运维
注:
Django的queryset的惰性机制
# <1>Django的queryset是惰性的
#
# Django的queryset对应于数据库的若干记录(row),通过可选的查询来过滤。例如,下面的代码会得
# 到数据库中名字为‘Dave’的所有的人:person_set = Person.objects.filter(first_name="Dave")
# 上面的代码并没有运行任何的数据库查询。你可以使用person_set,给它加上一些过滤条件,或者将它传给某个函数,
# 这些操作都不会发送给数据库。这是对的,因为数据库查询是显著影响web应用性能的因素之一。
#
# <2>要真正从数据库获得数据,你可以遍历queryset或者使用if queryset,总之你用到数据时就会执行sql.
# 为了验证这些,需要在settings里加入 LOGGING(验证方式)
# obj=models.Book.objects.filter(id=3)
# # for i in obj:
# # print(i)
#
# # if obj:
# # print("ok")
#
# <3>queryset是具有cache的
# 当你遍历queryset时,所有匹配的记录会从数据库获取,然后转换成Django的model。这被称为执行
# (evaluation).这些model会保存在queryset内置的cache中,这样如果你再次遍历这个queryset,
# 你不需要重复运行通用的查询。
# obj=models.Book.objects.filter(id=3)
#
# # for i in obj:
# # print(i)
# ## models.Book.objects.filter(id=3).update(title="GO")
# ## obj_new=models.Book.objects.filter(id=3)
# # for i in obj:
# # print(i) #LOGGING只会打印一次
#
# <4>
# 简单的使用if语句进行判断也会完全执行整个queryset并且把数据放入cache,虽然你并不需要这些
# 数据!为了避免这个,可以用exists()方法来检查是否有数据:
#
# obj = Book.objects.filter(id=4)
# # exists()的检查可以避免数据放入queryset的cache。
# if obj.exists():
# print("hello world!")
#
# <5>当queryset非常巨大时,cache会成为问题
#
# 处理成千上万的记录时,将它们一次装入内存是很浪费的。更糟糕的是,巨大的queryset可能会锁住系统
# 进程,让你的程序濒临崩溃。要避免在遍历数据的同时产生queryset cache,可以使用iterator()方法
# 来获取数据,处理完数据就将其丢弃。
# objs = Book.objects.all().iterator()
# # iterator()可以一次只从数据库获取少量数据,这样可以节省内存
# for obj in objs:
# print(obj.name)
# #BUT,再次遍历没有打印,因为迭代器已经在上一次遍历(next)到最后一次了,没得遍历了
# for obj in objs:
# print(obj.name)
#
# #当然,使用iterator()方法来防止生成cache,意味着遍历同一个queryset时会重复执行查询。所以使
# #用iterator()的时候要当心,确保你的代码在操作一个大的queryset时没有重复执行查询
#
# 总结:
# queryset的cache是用于减少程序对数据库的查询,在通常的使用下会保证只有在需要的时候才会查询数据库。
# 使用exists()和iterator()方法可以优化程序对内存的使用。不过,由于它们并不会生成queryset cache,可能
# 会造成额外的数据库查询。