先创建ORM模型
在models.py中县创建几个需要使用到例子的模型
# -*- coding: UTF-8 -*- from django.db import models class Author(models.Model): "作者模型" name = models.CharField(max_length=100) age = models.IntegerField() email = models.EmailField() class Meta: #该名称不能更改 db_table = ‘author‘ #映射到数据库中为你自定义的名字,不设置这个默认为 包名_表名 映射到数据库 class Publisher(models.Model): "出版社模型" name = models.CharField(max_length=300) class Meta: db_table = ‘publisher‘ class Book(models.Model): "book模型" name = models.CharField(max_length=300) pages = models.IntegerField() price = models.FloatField() rating = models.FloatField() author = models.ForeignKey(Author,on_delete = models.CASCADE) publisher = models.ForeignKey(Publisher,on_delete=models.CASCADE) class Meta: db_table = ‘book‘ class BookOrder(models.Model): "图书订单模型" book = models.ForeignKey("Book",on_delete=models.CASCADE) price = models.FloatField() class Meta: db_table = ‘book_order‘
1.filter : 将满足条件的数据提取出来(filter的方法可以查看一下之前的笔记)
from django.http import HttpResponse from .models import Book from django.db.models import Q #因为filter是同属QuerySet对象,可以链式调用 books = Book.objects.filter(id__gte=2).filter(~Q(id=3)) #找到Book表下id字段大于或者等2的数据但是不包含这个id=3的数据
2.exclude : 将满足条件的数据去除掉
#因为filter是同属QuerySet对象,可以链式调用 books = Book.objects.filter(id__gte=2).exclude(id=3) #找到Book表下id字段大于或者等2的数据,然后去除这个id=3的数据
3.annotate : 给对象添加一个查询表达式(例:聚合函数,F表达式,Q表达式,Func表达式等)的新字段
from .models import Book,Author from django.db.models import Q,F #获得图书的名称(Book表下)以及作者的名称(Author表下,在Book下使用别的表的数据,是通过小写调用的) books = Book.objects.annotate(author_name=F(‘author__name‘)) #这个author_name就是你自定义的新字段名称了,接收F(‘author__name‘)的值,关于F表达式的使用,看之前的笔记
#annotate详情看之前的笔记"聚合函数的使用"
4.order_by : 排序,默认从小到大
#1.根据创建时间从小到大进行排序 orders = BookOrder.objects.order_by(‘create_time‘) #在BookOrder表下中对create_time字段进行排序,加上 - 就是从倒序开始 #2.根据创建时间从大到小进行排序 # orders = BookOrder.objects.order_by(‘-create_time‘) #在BookOrder表下中对create_time字段进行排序,加上 - 就是从倒序开始 #3.先根据create_time字段进行排序,如果create_time字段中的数据想等,那么就根据price字段从大到小排序 # orders = BookOrder.objects.order_by(‘-create_time‘,‘-price‘) #在BookOrder表下中对create_time字段进行大到小排序,加上 - 就是从倒序开始 #4.根据外键关联上的某表中的某个字段进行排序 # orders = BookOrder.objects.order_by(‘book__rating‘) #在BookOrder表下对Book表下的rating字段进行小到大的排序,大到小的话order_by(‘-book__rating‘)加个-号 #这里的Book表是book的原因是创建关联后就django就会创建一个调用这个表的默认查询方法,就是该表的小写,如果想更改,在该表中使用Meta类来更改 #额外,需要注意的事项,使用order_by链式的话,那么最后的order_by会覆盖前面的 orders = BookOrder.objects.order_by(‘create_time‘).order_by(‘price‘) #order_by(‘price‘)覆盖了前面的order_by(‘create_time‘),也就是只会执行order_by(‘price‘)方法,默认从小到大排序 #对1,2,3,4的统一输出 for order in orders: print(‘%s/%s‘%(order.id,order.create_time))
也可以直接在创建模型的时候使用Meta类先进行排序
class BookOrder(models.Model): "图书订单模型" book = models.ForeignKey("Book",on_delete=models.CASCADE) price = models.FloatField() class Meta: db_table = ‘book_order‘ ordering = "[‘-create_time‘,‘price]" #这表中的create_time从大到小排序,如果这个字段的值相同,那么就按照price字段从小到大排序,加了-号是大到小排序,默认为小到大排序 接下来直接在views.py中直接使用即可 orders = BookOrder.objects.all() for order in orders: print()
在该表下根据其他表的字段进行排序
#提取Book表下外键关联的bookorder表下的id字段的总数,再根据这个总数从大到小排序 books = Book.objects.annotate(order_nums=Count(‘bookorder__id‘)).order_by("-order_nums") for book in books: print()
values : 获取指定字段的值,如果不传值的话就会返回全部
#只获取 id 和 name 字段的值 books = Book.objects.values(‘id‘,‘name‘) print(type(books)) #是queryset对象,不过这对象存储的是字典,不再是模型了 for book in books: print()
在该表下获取其他表下的字段
books = Book.objects.values(‘id‘,‘name‘,author_name=F(‘author__name‘)) #获取author表下的name字段,使用自定义的author_name(不能和模型上已拥有的字段相同,注意,这里的author_name是自己随意取的) ,就是更改author__name该字段的名字 print(type(books)) #是queryset对象,不过这对象存储的是字典,不再是模型了 for book in books: print()
还可以使用聚合函数
books = Book.objects.values(‘id‘,‘name‘,order_nums=Count(‘author__name‘)) #获取author表下的name字段的总数,使用自定义的order_nums来保存 for book in books: print(‘%s/%s‘%(book.id,book.create_time))
values_list : 直接根据所传的参数返回一个queryset,以元祖的形式保存,不传参数返回全部数据
#也就是不返回name,id这些字段名称了,直接返回这个字段中的数据(可使用for循环显示出来) books = Book.objects.values_list(‘id‘,‘name‘) for book in books: pass
#如果值传输一个字段参数的时候,那么就需要使用flat=True将这返回的queryset镀锡i昂所存储的元祖形式该为字符串形式 #注意:只有在传这么一个参数的时候才能使用这个 books = Book.objects.values_list(‘name‘,flat=True) for book in books: pass
all : 返回表中的所有数据,能够返回获得queryset对象的数据,方便用来遍历
books = Book.objects.all() #获得Book表下的所有数据 for book in books: book.name #获得名字
select_related : 主要用于做数据优化,也就是和all类似,但是all会做很多次查询,只能用在多对一的关系
主要就是将某字段中的值全部提取出来,保存在内存中,下次调用就不用反复查询多次,查询一次就行了
books = Book.objects.select_related(‘author‘) #获得Book表下的author字段的数据,淡然也可以传递多个参数 for book in books: print(book.author.name)
prefetch_related : 主要用于数据优化,可以做一对多,多对多这样的关系查询数据
一般我们再查询数据时,都是使用的django自动为我们创建的默认方法 小写的表名_set
但是每次调用的时候都会执行一次这个查询,这样的话数据量大的话处理就很麻烦了
使用prefetch_related使用到的时候只需要查询一次就可以了
books = Book.objects.prefetch_related(‘bookorder_set‘) #获得Book表外键关联的BookOrder表的django自动为你创建的查询方法 bookorder_set,也就是获取BookOrder表下的所有数据,然后保存在内存中,这样的话查询两次就行了 for book in books: print(book.name)
获取表下某个的数据
books = Book.objects.prefetch_related(‘author‘) #获取Book表下author字段中的数据,保存在内存中 for book in books: print(book.author.name) #再次使用的话查询一次就可以了,因为保存相关数据在了内存中 #因为我们使用的 小写的表名_set 以及 all 方法,都是会反复不断的执行sql语句的
注意:在使用prefetch_related 或者 select_related 后,再次使用filter的的话,那么之前的prefetch_relaooted 以及 select_related 等就不会在起作用了,一样反复查询多次了
Prefetch : 如果想使用filter在做一个筛选的话,就需要使用这个了
from django.db.models import Prefetch #需要导入该方法 #也就是我想要获取Book表下的price字段,正常来说直接使用prefetch_relaooted就可以了,但是我还想使用filter筛选数据 #比如我只想获取price大于90的数据,那么就需要使用filter来筛选,但是使用了filter的话,那么prefetch_relaooted方法就是失效, #所以需要使用Prefetch先做一个预设,统一拿到你想要的数据,然后再使用 小写的表名_set.all() 正常获取数据,然后输出即可 prefetch = Prefetch("bookorder_set",queryset=BookOrder.objects.filter(price__gte=90)) books = Book.objects.prefetch_related(prefetch) for book in books: print(book.name) orders = book.bookorder_set.all() #之前的预设做好了以后这步就这样写,不用改 for order in orders: print(order.id)
defer : 过滤掉你想要过滤的字段
#过滤掉name字段 books = Book.objects.defer(‘name‘) #过滤掉Book表下的name字段的数据,也就是返回除了name字段以外的数据 for book in books: pass
如果你过滤了还想要再次获得这个name数据,也是可行的,但是会根据你的循环次数发起多次请求
for book in books: print(book.name) #这样就行了,根据你的循环次数来发起请求获取数据
only : 和defer类似,也就是我只提取某个字段,但是有一点,你给不给id这个字段都会提取到
books = Book.objects.only(‘name‘) for book in books: print(‘%s/%s‘%(book.id,book.name)) #可以看到id字段的数据和name字段的数据都会被提取出来了 print(book.price) #因为这里没有提取出来,所以你这里的话查询也是可以的,也是一样,重新发起多次的查询请求
get : 只能返回满足条件的一个值,如果这个值能返回多个结果或者不存在的数据,那么就会报错
#获取id=1的一条数据 √ book = Book.objects.get(pk=1) #找到Book表下主键或者id等于1的一条数据 print(book) #获取id大于等于1的多条数据 × book = Book.objects.get(pk_gte=1) print(book) #会报错,因为get只能接收一个返回值 #如果是book = Book.objects.get(pk=100) #获得Book表下pk=100的这条数据,不存在的话也会报错
create : 给表创建数据并且保存在数据库中
#平常我们保存数据的方法是 book = Book(name=‘王老五‘) #在Book表下的name字段创建一条数据 book.save() #将这条数据保存在数据库中 #这样子的话比较麻烦,使用create方法就可以省略繁琐的步骤 book = Book.objects.create(name=‘王老五‘) # 这一步就相当于之前的那两步了,创建数据并且保存数据
get_or_create : 根据条件进行查找数据,找到了就返回,找不到的话就会创建这条数据
book = Book.objects.get_or_create(title=‘默认分类‘) #查询Book表下的titile字段上的这一条数据,找到了就返回该数据,找不到就默认创建这条数据
bulk_create : 可以一次性创建多条数据并且保存,create的话只能创建一条
books = Book.objects.bulk_create([ #在Book表下创建两条数据并且保存 Book(name=‘aa‘), Book(name=‘bb‘) ])
count : 获得数据的个数
#一般我们获取表中一共有多少条数据 count = Book.objects.all() #获取Book表下的所有数据 print(len(count)) #使用len方法求出数据的总数,但是这个len方法是很不效率的 #推荐使用count方法查询数据总数 count = Book.objects.count() #获取Book表下的数据总数 print(count)
first 和 last 获取queryset()第一条数据和最后一条数据
book = Book.objects.all().first() # 获取Book表中中的第一条数据 book = Book.objects.all().last() # 获取Book表中中的最后一条数据
aggregate 和 annotate 执行聚合函数(聚合函数有:Count 、Max 、Min 、Sum 等等)
例子 : 比如在求平均值 #1.aggregate 会将所有的值都会求出平均值(需要导入connection模块) def index(request): result = Book.objects(Avg(‘price‘)) #Avg不能直接使用,需要使用aggregate包住详情看1的写法 print(result) #2.annotate 的话就会一个额外的 group by的分组操作,然后在求出各个组的平均值 #求各组的平均值 #将Book表下关联的BookOrder(使用的话就django默认设置的小写)的price字段中根据id的不同分组,然后在求出各个组的平均值 books = Book.objects.annotata(price_avg=Avg(‘bookorder__price‘)) #将这个名称改了price_avg for book in books: print(‘%s/%s‘%(book.name,book.price_avg)) #price_avg在前面中已经更改了名称,不然就是默认的Avg
exists : 判断某个条件的数据是否存在
book = Book.objects.filter(name=‘李四‘).exists() #筛选出Book表下name字段中的李四这个数据,使用exists判断是否存在 print(book) #存在返回true,不存在返回False
distinct : 去除掉重复的数据
books = Book.objects.filter(price__get=80).distinct() #获取到Book表下的price字段中大于等80的不重复数据
注意事项 : 配合order_by 使用时
books = Book.objects.filter(price__get=80).order_by(‘bookorder__price‘).distinct() #这里一句一句来解释 #1.Book.objects.filter(price__get=80)获取到Book表下的price字段中大于等于80的数据, #2.order_by(‘bookorder__price‘),Book表与BookOrder之间有外键关联,就可以在Book表下使用关联那个表的小写形式来查询字段(该查询方法是关联后django自动创建的) #3.distinct() 然后再去掉重复的数据,也会讲bookorder表下的price字段中的数据也会算在一起,和之前的Book表下的price下相同也会一样输出
update : 更新数据
#使用update方法 Book.objects.update(price=F(‘price‘)+5) #直接在Book表下,通过F表达式获取到price字段的所有数据+5后返回,然后自动更新到数据库
delete : 删除数据
删除的话需要注意,如果你要删除的这个字段是有外键关联其他数据的,那么也会相对应的删除,也就是在删除的时候,需要查看你在使用ForeignKey的时候使用的参数也就是on_delete是设置的什么,需要查看一下,要对你的表非常熟悉
Book.objects.filter(id__gte=3).delete() #删除Book表下id大于等3的数据,注意,如果存在外键这个级联关系,那么相对应的数据也会跟着删除
切片操作 : 也就是查找数据时,只取其中的一部分
(建议使用,因为是直接在数据库层面进行截取,而不是取出数据在截取)
books = Book.objects.get_queryset()[0:2] #需要使用到get_queryset方法才能使用切片,获取到Book表下的0-2的数据,不包含2 for book in books: print(book)
还有另一种方法:
books = Book.objects.all()[0:2] for book in books: print(book)