Django:QuerySet对象

  • QuerySet API
    我们通常做查询操作的时候都是通过"模型名字.objects"的方式进行操作的。其实"模型名字.objects"是一个"django.db.models.manager.Manager"对象,而Manager这个类是一个"空壳"的类,它本身是没有任何的属性和方法的。它的方法全部都是通过Python以动态添加的方式,从QuerySet类中拷贝过来的


    图片.png

    注:本章的所有例子,大都基于这个模型类

from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField(default=20)
    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):
    name = models.CharField(max_length=255)
    pages = models.IntegerField()
    price = models.FloatField()
    rating = models.FloatField()
    author_a =models.ForeignKey("Author",on_delete=models.CASCADE)
    publisher_a = models.ForeignKey("Publisher", on_delete=models.CASCADE)
    create_time = models.DateTimeField(auto_now_add=True)
    update_time = models.DateTimeField(auto_now=True)
    class Meta:
        db_table = "book"

例1:
⑴打印"模型名字.objects"

from django.http import HttpResponse
from app01.models import Author,Book,Publisher

def index(request):
    print(type(Book.objects))
    return HttpResponse("success")

结果:<class 'django.db.models.manager.Manager'>

⑵查看"Manager"类
①通过步骤1的输出可以看到"模型名字.objects"返回的是一个"Manager"对象,因此查看"Manager"类
②导入"Manager"类:from django.db.models.manager import Manager
③选中"Manager"后Ctrl+B:查看源码


图片.png

⑶查看"from_queryset"方法


图片.png

注:上面的源码什么的我是看得不是很懂的,只是想说明下:"objects"对象下面的方法都是从"QuerySet"对象下拷贝过来的,"QuerySet"对象对象下的方法,可以直接在"objects"对象下调用
返回新的QuerySet的方法
1、在使用QuerySet进行查找操作的时候,可以提供多种操作。比如过滤完后还要根据某个字段进行排序,那么这一系列的操作我们可以通过一个非常流畅的"链式调用"的方式进行。比如要从文章中获取标题为123,并且提取后要将结果根据发布时间进行排序,那么就可以通过下面的方式来完成:"article=Article.objects.filter(title='123').order_by('create_time')"
2、可以看到order_by方法是直接在filter()方法执行后调用的。这说明filter()方法返回的是一个拥有order_by方法的对象。而这个对象正是一个新的QuerySet对象,因此可以使用order_by方法(当然QuerySet对象还可以使用其他方法,这里只是以filter方法和order_by方法举例)
3、只要返回的数据是一个QuerySet对象,那么就可以调用QuerySet对象方法(链式调用或分步调用)。特别注意object对象中的方法是复制QuerySet对象下的方法的,因此object对象也可以直接调用QuerySet对象方法

4、本章介绍的都是QuerySet对象方法,因此这些方法都是可以组合使用的(除了有些QuerySet对象方法返回的不是QuerySet对象)
例1_1:

    info = User.objects.filter(create_time__gt="2020-10-14 21:58:48").filter(telephone=13355509333)
    print(info)
    #<QuerySet [<User: User object (8)>]>
    user = info = User.objects.filter(create_time__gt="2020-10-14 21:58:48")
    print(type(user))
    print(user.filter(telephone=13355509333))
    # <class 'django.db.models.query.QuerySet'>
    # <QuerySet [<User: User object (8)>]>

注:
1、上面例子中分别使用了两种写法来实现同一个查询
2、filter()本来就是QuerySet对象下面的方法:其返回的是一个QuerySet对象,因此这个QuerySet对象又可以继续使用QuerySet对象下面的方法(也就是这两章将要介绍的方法),这里只是以两个filter()方法为例
3、一般采用的都是第一种写法,也就是"链式调用"

QuerySet对象方法

filter()

1、作用:将满足条件的数据提取出来,返回一个新的QuerySet对象
2、不论查询结果中有多少条数据都可以正常返回,无数据时也会返回一个空的QuerySet对象
例2:
⑴查看数据

图片.png

⑵编辑视图:首次调用

from django.http import HttpResponse
from app01.models import Author,Book,Publisher

def index(request):
    books=Book.objects.filter(id__gte=1)
    print(books)
    print(type(books))
    return HttpResponse("success")
结果:
<QuerySet [<Book: Book object (1)>, <Book: Book object (2)>, <Book: Book object (3)>, <Book: Book object (4)>]>
<class 'django.db.models.query.QuerySet'>

⑶编辑视图:继续调用

from django.http import HttpResponse
from app01.models import Author,Book,Publisher
from django.db.models import Q

def index(request):
    books=Book.objects.filter(id__gte=1)
    books=books.filter(~Q(id__exact=3))#也可以写成~Q(id=3),但不能写成(id!=3)
    print(books)
    print(type(books))
    return HttpResponse("success")
结果:
<QuerySet [<Book: Book object (1)>, <Book: Book object (2)>, <Book: Book object (4)>]>
<class 'django.db.models.query.QuerySet'>

注:
上面例子中在过滤"id不等于3"时,不能写成"books = books.filter(id!=3)":如果这样写的话会报错'bool' object is not iterable
⑴在Python中"!="和"=="等返回的是一个bool类型的值,但是这种类型的值不能使用在Django的模型中
⑵因此在Django在过滤"不等"条件时,需要换种处理方式:先使用Q表达式找出"等于这个值"的值,然后在进行取反操作:books.filter(~Q(id=3))

⑷编辑视图:优化

books=Book.objects.filter(id__gte=1).filter(~Q(id__exact=3))

例2_1:
⑴编辑模型

from django.db import models
class UserInfo(models.Model):
    id = models.AutoField('序号', primary_key=True)
    username = models.CharField('姓名', max_length=50)

    def __str__(self):
        return self.name

⑵查看数据


图片.png

⑶编辑模板:在模板使用变量来承接视图视图函数传递过来的值{{ img.url }}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>图书详情</title>
    {% load static %}
    <link rel="shortcut icon" href="{% static 'app01/img/favicon.ico' %}" type="image/x-icon">
</head>
<body>
    {% for img in imgs %}
        <img src="{{ img.url }}" alt="" height="200" width="200">
        <!--就相当于是:<img src="/static/app01/img/two.jpg">-->
    {% endfor %}
</body>
</html>
图片.png

⑷编辑视图

from django.shortcuts import render
from app01.models import Author,Book,Publisher,Img

def index(request):
    imgs=Img.objects.filter(username="张三").values("url")
    content={"imgs":imgs}
    print(content)#{'imgs': <QuerySet [{'url': '/static/app01/img/two.jpg'}]>}
    return render(request,"index.html",context=content)

注:
1、使用filter()等方法来查找数据时,返回的是一个QuerySet对象,QuerySet对象是不能直接使用"QuerySet对象名.列名"来获取具体某列的值:需要先使用for循环来遍历得到每条数据的模型类,然后才能使用"模型类名.列名"来获取具体某列的值。这里的列名指的是模型类中对应列的属性名(模型类中的列名)
2、比如上面这个例子中就是在:模板类使用for标签来遍历视图函数传递过来的QuerySet对象,当然这个遍历也可以在视图函数中使用for循环来实现


get()方法
例3:
1、作用:获取满足条件的数据,直接返回的是一个模型且只有一条数据,因此可以直接使用"模型名(实例名).属性名"来获取具体列的值
2、这个函数只能返回一条数据,并且如果给的条件能查询出多条数据的话,这个方法就会抛出异常;如果给的条件没有查询出任何数据的话,也会抛出异常。因此这个方法在获取数据的时候只能有且只有一条数据(通常使用于主键id来进行查询)

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,Img
def index(request):
    books = Book.objects.get(pk=1)
    print(type(books))
    print(books.name)
    return HttpResponse("success")
结果:
<class 'app01.models.Book'>
西游记

all()
作用:获取这个ORM模型的QuerySet对象。因为返回的是模型中的所有数据(本身不会有过滤作用),并且所有的这些数据是简单的放在一个QuerySet对象的
例4:
⑴编辑视图

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,Img
def index(request):
    books=Book.objects.all()
    print(type(books))
    for book in books:
        print(book)
    return HttpResponse("success")
结果:
<class 'django.db.models.query.QuerySet'>
Book object (1)
Book object (2)
Book object (3)
Book object (4)

⑵编辑视图:用在子查询中

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,Img
def index(request):
    #查询作者是“吴承恩”的所有图书(子查询:反向查询)
    author=Author.objects.filter(name="吴承恩").first()
    #不使用first()方法时,返回的是一个QuerySet对象
    print(type(author))
    books=author.book_set.all()#返回结果必须是一个模型类时才能使用“子表模型小写_set”
    print(type(books))
    for book in books:
        print(book)
    return HttpResponse("success")
结果:
<class 'app01.models.Author'>
<class 'django.db.models.query.QuerySet'>
Book object (1)
Book object (5)

⑶编辑视图

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,Img
def index(request):
    #查询作者是“吴承恩”的所有图书(join查询:反向查询)
    books=Author.objects.filter(name="吴承恩").values("book__name")
    print(type(books))
    for book in books:
        print(book)
    # 查询作者是“吴承恩”的所有图书(join查询:正向查询)
    books_1=Book.objects.filter(author_a__name="吴承恩")
    print(books_1)
    for book in books_1:
        print(book.name)
    return HttpResponse("success")
结果:
<class 'django.db.models.query.QuerySet'>
{'book__name': '西游记'}
{'book__name': '西游记后传'}

<QuerySet [<Book: Book object (1)>, <Book: Book object (5)>]>
西游记
西游记后传

注:从上面例子可以看出
1、基于对象的查询(子查询)和基于双下划线的查询(join查询):在某些时候是可以达到同一目的的


values()
作用:用来提取指定的字段数据。默认情况下会把表中所有的字段全部提取出来,可以使用values()方法来指定只返回哪些字段,并且使用了values方法后,提取出的QuerySet对象中的数据模型不是模型,而是在valuses中指定的字段和值形成的字典
例5:
⑴编辑视图(直接查询Book模型类中的数据)

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,Img
def index(request):
    #直接查询Book模型类中的数据
    books=Book.objects.values("name","price")
    print(type(books))
    for book in books:
        print(book)
    return HttpResponse("success")
结果:
<class 'django.db.models.query.QuerySet'>
{'name': '西游记', 'price': 45.0}
{'name': 'python3.6', 'price': 68.0}
{'name': 'c++', 'price': 55.0}
{'name': '史记', 'price': 120.0}

注:从上面例子可以看出
1、有时候我们在表中查询数据的时候,并不是想把所有的字段都提取出来。我们有可能只是想要查询其中的几个字段,这个时候就可以使用values()方法了
2、values()方法返回值同样也是一个QuerySet对象,但是这个QuerySet对象中装的就不再是模型了,而是查询出来的数据组成的字典了
3、values()方法的作用只是返回指定字段的值,其并没有过滤作用,因此values()方法更多的是和filter()等方法一起使用的
例5_1:
⑴编辑视图:join正向查询(查询图书id大于2的作者)

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,Img
def index(request):
    books = Book.objects.filter(id__gt=2).values("name","price","author_a__name")
    print(type(books))
    for book in books:
        print(book)
    return HttpResponse("success")
结果:
<class 'django.db.models.query.QuerySet'>
{'name': 'c++', 'price': 55.0, 'author_a__name': '谭浩强'}
{'name': '史记', 'price': 120.0, 'author_a__name': '王五'}
{'name': '西游记后传', 'price': 36.0, 'author_a__name': '吴承恩'}
图片.png

⑵编辑视图:join反向查询(查询作者id大于1的图书)

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,Img
def index(request):
    #查询作者id大于1的图书(反向查询:小写子表模型类名__主表待查询的字段名)
    books = Author.objects.filter(id__gt=1).values("name","email","book__name")
    print(type(books))
    for book in books:
        print(book)

    #查询作者id大于1的图书(正向查询:子表外键属性名__主表待查询的字段名)
    books_1 = Book.objects.filter(author_a__id__gt=1).values("name")
    #books_1 = Book.objects.filter(author_a_id__gt=1).values("name")#这么写也可以
    print(books_1)
    return HttpResponse("success")

结果:
<class 'django.db.models.query.QuerySet'>
{'name': '吴承恩', 'email': 'zhangsan@126.com', 'book__name': '西游记'}
{'name': '吴承恩', 'email': 'zhangsan@126.com', 'book__name': '西游记后传'}
{'name': '李四', 'email': 'lisi@126.com', 'book__name': None}
{'name': '王五', 'email': 'wangwu@126.com', 'book__name': '史记'}
<QuerySet [{'name': '西游记'}, {'name': '西游记后传'}, {'name': '史记'}]>
图片.png

图片.png

⑶编辑视图(查询图书id大于1的作者)

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,Img
from django.db.models import Q,F

def index(request):
    #查询图书id大于1的作者(反向查询:小写子表模型类名__主表待查询的字段名)
    books = Author.objects.filter(book__id__gt=1).values("name","email")
    print(type(books))
    for book in books:
        print(book)

    #查询图书id大于1的作者(正向查询:子表外键属性名__主表待查询的字段名)
    books_1 = Book.objects.filter(id__gt=1).values("author_a__name")
    print(books_1)
    return HttpResponse("success")

结果:
<class 'django.db.models.query.QuerySet'>
{'name': '谭浩强', 'email': 'thq@126.com'}
{'name': '谭浩强', 'email': 'thq@126.com'}
{'name': '吴承恩', 'email': 'zhangsan@126.com'}
{'name': '王五', 'email': 'wangwu@126.com'}
<QuerySet [{'author_a__name': '谭浩强'}, {'author_a__name': '谭浩强'}, {'author_a__name': '吴承恩'}, {'author_a__name': '王五'}]>

⑷编辑视图(进行关联字段查询时指定变量名:使用F表达式)

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,Img
from django.db.models import Q,F
def index(request):
    books = Book.objects.filter(id__gt=1).values(authorName=F("author_a__name"))
    print(type(books))
    for book in books:
        print(book)
    return HttpResponse("success")
结果:
<class 'django.db.models.query.QuerySet'>
{'authorName': '谭浩强'}
{'authorName': '谭浩强'}
{'authorName': '吴承恩'}
{'authorName': '王五'}
图片.png

⑸编辑视图:结合聚合函数


图片.png

注:
1、在进行关联字段查询时,如果想更改一下返回结果中的键名时,可以使用关键字参数(加F表达式)来指定返回数据的键名
2、不过,自定义的名字不能和模型上本身拥有的字段名字一样,不然会报错
3、如果调用values()方法时,没有传递任何参数,那么会获取这个模型上的所有字段以及对应的值形成的字典


values_list()
作用:类似于values()方法,只不过返回的QuerySet对象中存储的不是字典而是元组
例6:
⑴编辑视图

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,Img
def index(request):
    books = Book.objects.filter(id__gt=1).values_list("name","price")
    print(type(books))
    for book in books:
        print(book)
    return HttpResponse("success")
结果:
<class 'django.db.models.query.QuerySet'>
('python3.6', 68.0)
('c++', 55.0)
('史记', 120.0)
('西游记后传', 36.0)

⑵编辑视图

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,Img
def index(request):
    books = Book.objects.filter(id__gt=1).values_list("name",flat=True)
    print(type(books))
    for book in books:
        print(book)
    return HttpResponse("success")
结果:
<class 'django.db.models.query.QuerySet'>
python3.6
c++
史记
西游记后传

注:
1、values_list()方法如果只返回一个字段,那么可以给其添加一个flat=True的参数:返回结果就不是一个元组了,而只是这个字段的值
2、flat=True参数只能在只返回一个字段时使用,如果返回的字段数大于1,那么就会报错
3、values()方法和values_list()方法的作用只是返回指定字段的值,并没有过滤作用,因此两个方法更多的是和filter()等方法一起使用的(先通过其他方法过滤查询出数据,然后选择是否使用values()方法和values_list()方法来获取指定字段的值)


exclude()
作用:排除满足条件的数据,返回一个新的QuerySet对象
例7:

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,Img
def index(request):
    #先过滤id>=1的数据,然后在排除id=3的数据
    books = Book.objects.filter(id__gte=1).exclude(id=3)
    print(type(books))
    for book in books:
        print(book)
    return HttpResponse("success")
结果:
<class 'django.db.models.query.QuerySet'>
Book object (1)
Book object (2)
Book object (4)
Book object (5)

annotate()
作用:给QuerySet中的每个对象都添加一个使用查询表达式(可以是聚合函数、F表达式、Q表达式、Func表达式)的新字段
例8:查询每一本书的作者
⑴编辑视图:常规操作

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,Img
from django.db.models import Q,F

def index(request):
    """
    查找每一本书的作者。先通过在子表中找到符合条件的图书,
    然后再通过正向查询(外键字段名.主表待查询字段名)来找到每本图书对应的作者,
    不可以写成book.author_a__name,会报错:'Book' object has no attribute 'author_a__name
    在整个过程中,对数据库进行了两次查询
    """
    books = Book.objects.filter(id__gte=1)
    print(type(books))
    for book in books:
        print(book.name,book.author_a.name)
    return HttpResponse("success")
结果:
<class 'django.db.models.query.QuerySet'>
西游记 吴承恩
python3.6 谭浩强
c++ 谭浩强
史记 王五
西游记后传 吴承恩

⑵编辑视图(使用annotate)

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,Img
from django.db.models import Q,F
def index(request):
    #查找每一本书的作者
    books = Book.objects.annotate(author_name=F("author_a__name"))
    print(type(books))
    for book in books:
        print(book.name,book.author_a.name)
    return HttpResponse("success")
结果:
<class 'django.db.models.query.QuerySet'>
西游记 吴承恩
python3.6 谭浩强
c++ 谭浩强
史记 王五
西游记后传 吴承恩
图片.png

order_by()
作用:指定将查询的结果根据某个字段进行排序。如果要倒叙排序,那么可以在这个字段的前面加一个负号
例9:
⑴编辑视图

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,Img
def index(request):
    #查找每一本书的作者
    books = Book.objects.order_by("create_time")
    print(type(books))
    for book in books:
        print(book.name,book.create_time)
    return HttpResponse("success")
结果:
<class 'django.db.models.query.QuerySet'>
史记 2016-03-16 00:00:00+00:00
c++ 2020-10-01 00:00:00+00:00
python3.6 2022-05-04 16:23:39+00:00
西游记 2022-05-07 16:22:28+00:00
西游记后传 2022-05-08 00:00:00+00:00

⑵增加模型类

class BookOrder(models.Model):
    #图书订单模型
    book_1=models.ForeignKey("Book",on_delete=models.CASCADE)
    price=models.FloatField()
    create_time=models.DateTimeField(auto_now_add=True,null=True)
    class Meta():
        db_table="boo_order"

⑶查看数据


图片.png

⑷编辑视图

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,BookOrder,Img
def index(request):
    """根据create_time从大到小排序"""
    books = BookOrder.objects.order_by("-create_time")
    """先根据create_time从小到大排序,如果相同根据price从小到大排序"""
    books = BookOrder.objects.order_by("create_time","price")
    """根据订单的图书的评分排序"""
    orders= BookOrder.objects.order_by("book_1__rating")
    for order in orders:
        print(order.id,order.book_1.name,order.book_1.rating)
    return HttpResponse("success")
结果:
3 c++ 0.82
2 python3.6 0.88
4 西游记 0.9
1 史记 0.95
图片.png

⑸模型类的ordering属性


图片.png

select_related()
1、作用:在提取某个模型的数据的同时,也提前将相关联的数据提取出来
2、比如:提取文章数据时,可以使用select_related()方法将Author模型类中的数据提取出来,以后再使用article.author的时候就不需要再次去访问数据库了,可以减少数据库查询的次数
3、单独使用select_related()方法时是获取的全部数据,因此可以先使用filter()等方法过滤出数据后,再使用select_related()方法(这篇讲的都是QuerySet对象的方法,因此只要是一个QuerySet对象,那么这篇文章中的所有方法基本上都可以混合使用)
4、select_related()只能从子表开始通过外键字段名来获取主表中的数据(一对多关系中),但是不能通过主表开始获取子表中的数据,这个方法只能用在外键的关联对象上,对于那种多对多的情况,不能使用这个方法来实现,而应该通过"prefetch_related"来实现
例10:
⑴编辑视图:常规方法

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,BookOrder,Img
def index(request):
    """查询所有图书的作者"""
    books = Book.objects.all()
    print(type(books))
    for book in books:
        """QuerySet对象遍历后返回的是具体的模型类,因此可以使用(子表实例名.外键名.主表待查询字段名)"""
        print(book.name, book.author_a.name)
    return HttpResponse("success")
结果:
<class 'django.db.models.query.QuerySet'>
西游记 吴承恩
python3.6 谭浩强
c++ 谭浩强
史记 王五
西游记后传 吴承恩

⑵编辑视图(使用select_related)

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,BookOrder,Img
def index(request):
    """查询所有图书的作者"""
    books = Book.objects.select_related("author_a","publisher_a")
    """参数为外键名,参数可以为多个"""
    print(type(books))
    """遍历QuerySet对象,返回每个数据的模型类,进而可以使用‘模型类.字段名’获取某个字段的值"""
    for book in books:
        print(book.name, book.author_a.name,book.publisher_a.name)
    return HttpResponse("success")
结果:
<class 'django.db.models.query.QuerySet'>
西游记 吴承恩 人民文学出版社
python3.6 谭浩强 电子工业出版社
c++ 谭浩强 清华大学出版社
史记 王五 中华书局
西游记后传 吴承恩 人民文学出版社

⑶编辑视图(使用select_related)

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,BookOrder,Img
def index(request):
    """查询所有图书id>2的的作者"""
    books = Book.objects.filter(id__gt=2).select_related("author_a","publisher_a")
    """参数为外键名,参数可以为多个"""
    print(type(books))
    """遍历QuerySet对象,返回每个数据的模型类,进而可以使用‘模型类.字段名’获取某个字段的值"""
    for book in books:
        print(book.name, book.author_a.name,book.publisher_a.name)
    return HttpResponse("success")
结果:
<class 'django.db.models.query.QuerySet'>
c++ 谭浩强 清华大学出版社
史记 王五 中华书局
西游记后传 吴承恩 人民文学出版社

注:
1、使用常规方法时:每次在执行"book.author_a.name"时,即每次通过图书去查询作者时,都会去Author模型类中进行一次查询,这样的话就会耗性能,特别是有很多数据时

2、使用select_related()方法时,在查询Book模型类数据时,通过其方法中的参数就可以一次性的将关联表中的数据查询出来,后面就直接是获取Author中的数据了而不再需要再次查询

3、使用for循环来遍历QuerySet对象,然后依次返回每个数据的模型类,进而可以使用"模型类.字段名"来获取具体某个字段的值

4、只有返回数据为一个模型时,才能使用"模型类.字段名"来获取具体某个字段的值

5、注意:这个例子中是从子表到主表且表关系为一对多,因此主表中只会有一条数据,因此可以直接使用"模型类.字段名"来获取主表中具体某列的值
⑴如果是从主表到子表且表关系为一对多,因此子表中可能有多条或一条,如果子表数据为多条时,那么就需要先使用all()方法获取全部数据(此时为QuerySet对象),然后使用for循环遍历,然后才能使用"模型类.字段名"来获取子表中具体某列的值


prefetch_related()
1、作用:这个方法和select_related()方法类似,就是在访问多个表中的数据的时候,减少查询的次数
2、这个方法时为了解决多对一和多对多的关系的查询问题。例如要获取一个作者下的所有文章(一对多关系中:从主表到子表)
例11:
⑴编辑视图

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,BookOrder,Img
def index(request):
    """查询作者为吴承恩的所有图书"""
    authors=Author.objects.filter(name="吴承恩")
    print("type(authors):",type(authors))
    for author in authors:
        print("type(author):",type(author))
        print(author.name,author.book_set.all())
        """author.book_set.all():反向关系,得到Book对象(一个或多个)"""
        for book in author.book_set.all():
            print(book.name)
    return HttpResponse("success")
结果:
type(authors): <class 'django.db.models.query.QuerySet'>
type(author): <class 'app01.models.Author'>
吴承恩 <QuerySet [<Book: Book object (1)>, <Book: Book object (5)>]>
西游记
西游记后传

⑵编辑视图(使用prefetch_related)

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,BookOrder,Img
def index(request):
    """查询作者为吴承恩的所有图书"""
    books=Author.objects.filter(name="吴承恩").prefetch_related("book_set")
    print(type(books))
    for book in books:
        print(type(book))
        print(book.name,book.book_set.all())
        """子表Book模型内有多条数据,因此先使用all()方法获取全部数据,
        然后再遍历使用‘模型类名.字段名’来获取具体某列的值"""
        for book in book.book_set.all():
            print(book.name)
    return HttpResponse("success")
结果:
<class 'django.db.models.query.QuerySet'>
<class 'app01.models.Author'>
吴承恩 <QuerySet [<Book: Book object (1)>, <Book: Book object (5)>]>
西游记
西游记后传

注:
使用"模型类名.列名"来获取某一个列具体的值时:
⑴前提是返回的是一个模型类,而不是一个QuerySet对象。如果是一个QuerySet对象,那么就需要通过for循环遍历来依次返回每个具体数据的模型类
⑵只有返回的数据是一条数据的模型类时,才能使用"模型类.字段名"来获取某一个列具体的值:如一对多中,子表到主表,主表肯定只有一条数据,那么就可以直接使用"模型类.字段名"来获取某一个列具体的值
⑶如果返回的是多条数据的模型类,那么就必须先使用for循环来遍历依次得到每条数据的模型类,然后才能使用"模型类.字段名"来获取某一个列具体的值:如一对多中,主表到子表,子表数据可以有一条或多条,当为多条时先使用all()来获取全部数据,然后遍历,再使用"模型类.字段名"
⑷其实不管使用什么方法,只要返回的是多条数据,那么都需要使用for循环来依次遍历出每条数据,然后才能使用"模型类名.列名"来获取某一个列具体的值。如果是对多条数据使用"模型类名.列名"的话肯定是不行的,都不知道获取的是哪条数据中的列值


defer()
1、作用:在一些表中,可能存在很多字段,但是一些字段的数据量可能是比较大的,而此时你又不需要。比如在获取文章列表的时候,文章的内容不是我们所需要的,因此这时候我们就可以使用defer()方法来过滤掉一些字段
2、defer()方法的作用与value()方法有点类似,只不过defer()方法返回的不是字典,而是模型
例12:

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,BookOrder,Img
from django.db import connection
def index(request):
    books=Book.objects.defer("price")
    print(type(books))
    print(books)
    for sql in connection.queries:
        print(sql)
    return HttpResponse("success")
图片.png

注:
1、从上面的SQL语句可以看到,查询文章的字段时,除了price,其他字段都查找出来了。当然,也可以使用book.price来获取这个文章的价格,但是会重新执行一个查询语句
2、defer()方法虽然能过滤字段,但是有些字段是不能过滤的,比如id列,即使你过滤了,也会提取出来


only()
作用:跟dfer()方法类似,只不过defer()方法是过滤指定的字段,而only是只提取指定的字段
例13:
⑴编辑视图:可以传入多个字段

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,BookOrder,Img
from django.db import connection
def index(request):
    books=Book.objects.only("price")
    print(type(books))
    print(books)
    for sql in connection.queries:
        print(sql)
    return HttpResponse("success")
图片.png

拓展
QuerySet对象特性
1、QuerySet对象是可迭代的、可切片的。在一定程度上感觉QuerySet对象具有很多序列的特性
2、另外,还可以对QuerySet对象集使用random.choice()方法:随机选择一个QuerySet对象

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容