django-QuerySet—API

先创建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)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

django-QuerySet—API

上一篇:Windows下ping命令常用参数及实例


下一篇:PHP一致性哈希