Django:QuerySet對象

  • QuerySet API
    我們通常做查詢操作的時候都是通過"模型名字.objects"的方式進(jìn)行操作的。其實(shí)"模型名字.objects"是一個"django.db.models.manager.Manager"對象,而Manager這個類是一個"空殼"的類,它本身是沒有任何的屬性和方法的。它的方法全部都是通過Python以動態(tài)添加的方式,從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")

結(jié)果:<class 'django.db.models.manager.Manager'>

⑵查看"Manager"類
①通過步驟1的輸出可以看到"模型名字.objects"返回的是一個"Manager"對象,因此查看"Manager"類
②導(dǎo)入"Manager"類:from django.db.models.manager import Manager
③選中"Manager"后Ctrl+B:查看源碼


圖片.png

⑶查看"from_queryset"方法


圖片.png

注:上面的源碼什么的我是看得不是很懂的,只是想說明下:"objects"對象下面的方法都是從"QuerySet"對象下拷貝過來的,"QuerySet"對象對象下的方法,可以直接在"objects"對象下調(diào)用
返回新的QuerySet的方法
1、在使用QuerySet進(jìn)行查找操作的時候,可以提供多種操作。比如過濾完后還要根據(jù)某個字段進(jìn)行排序,那么這一系列的操作我們可以通過一個非常流暢的"鏈?zhǔn)秸{(diào)用"的方式進(jìn)行。比如要從文章中獲取標(biāo)題為123,并且提取后要將結(jié)果根據(jù)發(fā)布時間進(jìn)行排序,那么就可以通過下面的方式來完成:"article=Article.objects.filter(title='123').order_by('create_time')"
2、可以看到order_by方法是直接在filter()方法執(zhí)行后調(diào)用的。這說明filter()方法返回的是一個擁有order_by方法的對象。而這個對象正是一個新的QuerySet對象,因此可以使用order_by方法(當(dāng)然QuerySet對象還可以使用其他方法,這里只是以filter方法和order_by方法舉例)
3、只要返回的數(shù)據(jù)是一個QuerySet對象,那么就可以調(diào)用QuerySet對象方法(鏈?zhǔn)秸{(diào)用或分步調(diào)用)。特別注意object對象中的方法是復(fù)制QuerySet對象下的方法的,因此object對象也可以直接調(diào)用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、上面例子中分別使用了兩種寫法來實(shí)現(xiàn)同一個查詢
2、filter()本來就是QuerySet對象下面的方法:其返回的是一個QuerySet對象,因此這個QuerySet對象又可以繼續(xù)使用QuerySet對象下面的方法(也就是這兩章將要介紹的方法),這里只是以兩個filter()方法為例
3、一般采用的都是第一種寫法,也就是"鏈?zhǔn)秸{(diào)用"

QuerySet對象方法

filter()

1、作用:將滿足條件的數(shù)據(jù)提取出來,返回一個新的QuerySet對象
2、不論查詢結(jié)果中有多少條數(shù)據(jù)都可以正常返回,無數(shù)據(jù)時也會返回一個空的QuerySet對象
例2:
⑴查看數(shù)據(jù)

圖片.png

⑵編輯視圖:首次調(diào)用

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")
結(jié)果:
<QuerySet [<Book: Book object (1)>, <Book: Book object (2)>, <Book: Book object (3)>, <Book: Book object (4)>]>
<class 'django.db.models.query.QuerySet'>

⑶編輯視圖:繼續(xù)調(diào)用

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")
結(jié)果:
<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)":如果這樣寫的話會報(bào)錯'bool' object is not iterable
⑴在Python中"!="和"=="等返回的是一個bool類型的值,但是這種類型的值不能使用在Django的模型中
⑵因此在Django在過濾"不等"條件時,需要換種處理方式:先使用Q表達(dá)式找出"等于這個值"的值,然后在進(jìn)行取反操作:books.filter(~Q(id=3))

⑷編輯視圖:優(yōu)化

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

⑵查看數(shù)據(jù)


圖片.png

⑶編輯模板:在模板使用變量來承接視圖視圖函數(shù)傳遞過來的值{{ 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">
        <!--就相當(dāng)于是:<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()等方法來查找數(shù)據(jù)時,返回的是一個QuerySet對象,QuerySet對象是不能直接使用"QuerySet對象名.列名"來獲取具體某列的值:需要先使用for循環(huán)來遍歷得到每條數(shù)據(jù)的模型類,然后才能使用"模型類名.列名"來獲取具體某列的值。這里的列名指的是模型類中對應(yīng)列的屬性名(模型類中的列名)
2、比如上面這個例子中就是在:模板類使用for標(biāo)簽來遍歷視圖函數(shù)傳遞過來的QuerySet對象,當(dāng)然這個遍歷也可以在視圖函數(shù)中使用for循環(huán)來實(shí)現(xiàn)


get()方法
例3:
1、作用:獲取滿足條件的數(shù)據(jù),直接返回的是一個模型且只有一條數(shù)據(jù),因此可以直接使用"模型名(實(shí)例名).屬性名"來獲取具體列的值
2、這個函數(shù)只能返回一條數(shù)據(jù),并且如果給的條件能查詢出多條數(shù)據(jù)的話,這個方法就會拋出異常;如果給的條件沒有查詢出任何數(shù)據(jù)的話,也會拋出異常。因此這個方法在獲取數(shù)據(jù)的時候只能有且只有一條數(shù)據(jù)(通常使用于主鍵id來進(jìn)行查詢)

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")
結(jié)果:
<class 'app01.models.Book'>
西游記

all()
作用:獲取這個ORM模型的QuerySet對象。因?yàn)榉祷氐氖悄P椭械乃袛?shù)據(jù)(本身不會有過濾作用),并且所有的這些數(shù)據(jù)是簡單的放在一個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")
結(jié)果:
<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()#返回結(jié)果必須是一個模型類時才能使用“子表模型小寫_set”
    print(type(books))
    for book in books:
        print(book)
    return HttpResponse("success")
結(jié)果:
<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")
結(jié)果:
<class 'django.db.models.query.QuerySet'>
{'book__name': '西游記'}
{'book__name': '西游記后傳'}

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

注:從上面例子可以看出
1、基于對象的查詢(子查詢)和基于雙下劃線的查詢(join查詢):在某些時候是可以達(dá)到同一目的的


values()
作用:用來提取指定的字段數(shù)據(jù)。默認(rèn)情況下會把表中所有的字段全部提取出來,可以使用values()方法來指定只返回哪些字段,并且使用了values方法后,提取出的QuerySet對象中的數(shù)據(jù)模型不是模型,而是在valuses中指定的字段和值形成的字典
例5:
⑴編輯視圖(直接查詢Book模型類中的數(shù)據(jù))

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,Img
def index(request):
    #直接查詢Book模型類中的數(shù)據(jù)
    books=Book.objects.values("name","price")
    print(type(books))
    for book in books:
        print(book)
    return HttpResponse("success")
結(jié)果:
<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、有時候我們在表中查詢數(shù)據(jù)的時候,并不是想把所有的字段都提取出來。我們有可能只是想要查詢其中的幾個字段,這個時候就可以使用values()方法了
2、values()方法返回值同樣也是一個QuerySet對象,但是這個QuerySet對象中裝的就不再是模型了,而是查詢出來的數(shù)據(jù)組成的字典了
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")
結(jié)果:
<class 'django.db.models.query.QuerySet'>
{'name': 'c++', 'price': 55.0, 'author_a__name': '譚浩強(qiáng)'}
{'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")

結(jié)果:
<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")

結(jié)果:
<class 'django.db.models.query.QuerySet'>
{'name': '譚浩強(qiáng)', 'email': 'thq@126.com'}
{'name': '譚浩強(qiáng)', 'email': 'thq@126.com'}
{'name': '吳承恩', 'email': 'zhangsan@126.com'}
{'name': '王五', 'email': 'wangwu@126.com'}
<QuerySet [{'author_a__name': '譚浩強(qiáng)'}, {'author_a__name': '譚浩強(qiáng)'}, {'author_a__name': '吳承恩'}, {'author_a__name': '王五'}]>

⑷編輯視圖(進(jìn)行關(guān)聯(lián)字段查詢時指定變量名:使用F表達(dá)式)

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")
結(jié)果:
<class 'django.db.models.query.QuerySet'>
{'authorName': '譚浩強(qiáng)'}
{'authorName': '譚浩強(qiáng)'}
{'authorName': '吳承恩'}
{'authorName': '王五'}
圖片.png

⑸編輯視圖:結(jié)合聚合函數(shù)


圖片.png

注:
1、在進(jìn)行關(guān)聯(lián)字段查詢時,如果想更改一下返回結(jié)果中的鍵名時,可以使用關(guān)鍵字參數(shù)(加F表達(dá)式)來指定返回?cái)?shù)據(jù)的鍵名
2、不過,自定義的名字不能和模型上本身擁有的字段名字一樣,不然會報(bào)錯
3、如果調(diào)用values()方法時,沒有傳遞任何參數(shù),那么會獲取這個模型上的所有字段以及對應(yīng)的值形成的字典


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")
結(jié)果:
<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")
結(jié)果:
<class 'django.db.models.query.QuerySet'>
python3.6
c++
史記
西游記后傳

注:
1、values_list()方法如果只返回一個字段,那么可以給其添加一個flat=True的參數(shù):返回結(jié)果就不是一個元組了,而只是這個字段的值
2、flat=True參數(shù)只能在只返回一個字段時使用,如果返回的字段數(shù)大于1,那么就會報(bào)錯
3、values()方法和values_list()方法的作用只是返回指定字段的值,并沒有過濾作用,因此兩個方法更多的是和filter()等方法一起使用的(先通過其他方法過濾查詢出數(shù)據(jù),然后選擇是否使用values()方法和values_list()方法來獲取指定字段的值)


exclude()
作用:排除滿足條件的數(shù)據(jù),返回一個新的QuerySet對象
例7:

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,Img
def index(request):
    #先過濾id>=1的數(shù)據(jù),然后在排除id=3的數(shù)據(jù)
    books = Book.objects.filter(id__gte=1).exclude(id=3)
    print(type(books))
    for book in books:
        print(book)
    return HttpResponse("success")
結(jié)果:
<class 'django.db.models.query.QuerySet'>
Book object (1)
Book object (2)
Book object (4)
Book object (5)

annotate()
作用:給QuerySet中的每個對象都添加一個使用查詢表達(dá)式(可以是聚合函數(shù)、F表達(dá)式、Q表達(dá)式、Func表達(dá)式)的新字段
例8:查詢每一本書的作者
⑴編輯視圖:常規(guī)操作

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

def index(request):
    """
    查找每一本書的作者。先通過在子表中找到符合條件的圖書,
    然后再通過正向查詢(外鍵字段名.主表待查詢字段名)來找到每本圖書對應(yīng)的作者,
    不可以寫成book.author_a__name,會報(bào)錯:'Book' object has no attribute 'author_a__name
    在整個過程中,對數(shù)據(jù)庫進(jìn)行了兩次查詢
    """
    books = Book.objects.filter(id__gte=1)
    print(type(books))
    for book in books:
        print(book.name,book.author_a.name)
    return HttpResponse("success")
結(jié)果:
<class 'django.db.models.query.QuerySet'>
西游記 吳承恩
python3.6 譚浩強(qiáng)
c++ 譚浩強(qiáng)
史記 王五
西游記后傳 吳承恩

⑵編輯視圖(使用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")
結(jié)果:
<class 'django.db.models.query.QuerySet'>
西游記 吳承恩
python3.6 譚浩強(qiáng)
c++ 譚浩強(qiáng)
史記 王五
西游記后傳 吳承恩
圖片.png

order_by()
作用:指定將查詢的結(jié)果根據(jù)某個字段進(jìn)行排序。如果要倒敘排序,那么可以在這個字段的前面加一個負(fù)號
例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")
結(jié)果:
<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"

⑶查看數(shù)據(jù)


圖片.png

⑷編輯視圖

from django.http import HttpResponse
from app01.models import Author,Book,Publisher,BookOrder,Img
def index(request):
    """根據(jù)create_time從大到小排序"""
    books = BookOrder.objects.order_by("-create_time")
    """先根據(jù)create_time從小到大排序,如果相同根據(jù)price從小到大排序"""
    books = BookOrder.objects.order_by("create_time","price")
    """根據(jù)訂單的圖書的評分排序"""
    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")
結(jié)果:
3 c++ 0.82
2 python3.6 0.88
4 西游記 0.9
1 史記 0.95
圖片.png

⑸模型類的ordering屬性


圖片.png

select_related()
1、作用:在提取某個模型的數(shù)據(jù)的同時,也提前將相關(guān)聯(lián)的數(shù)據(jù)提取出來
2、比如:提取文章數(shù)據(jù)時,可以使用select_related()方法將Author模型類中的數(shù)據(jù)提取出來,以后再使用article.author的時候就不需要再次去訪問數(shù)據(jù)庫了,可以減少數(shù)據(jù)庫查詢的次數(shù)
3、單獨(dú)使用select_related()方法時是獲取的全部數(shù)據(jù),因此可以先使用filter()等方法過濾出數(shù)據(jù)后,再使用select_related()方法(這篇講的都是QuerySet對象的方法,因此只要是一個QuerySet對象,那么這篇文章中的所有方法基本上都可以混合使用)
4、select_related()只能從子表開始通過外鍵字段名來獲取主表中的數(shù)據(jù)(一對多關(guān)系中),但是不能通過主表開始獲取子表中的數(shù)據(jù),這個方法只能用在外鍵的關(guān)聯(lián)對象上,對于那種多對多的情況,不能使用這個方法來實(shí)現(xiàn),而應(yīng)該通過"prefetch_related"來實(shí)現(xiàn)
例10:
⑴編輯視圖:常規(guī)方法

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對象遍歷后返回的是具體的模型類,因此可以使用(子表實(shí)例名.外鍵名.主表待查詢字段名)"""
        print(book.name, book.author_a.name)
    return HttpResponse("success")
結(jié)果:
<class 'django.db.models.query.QuerySet'>
西游記 吳承恩
python3.6 譚浩強(qiáng)
c++ 譚浩強(qiáng)
史記 王五
西游記后傳 吳承恩

⑵編輯視圖(使用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")
    """參數(shù)為外鍵名,參數(shù)可以為多個"""
    print(type(books))
    """遍歷QuerySet對象,返回每個數(shù)據(jù)的模型類,進(jìn)而可以使用‘模型類.字段名’獲取某個字段的值"""
    for book in books:
        print(book.name, book.author_a.name,book.publisher_a.name)
    return HttpResponse("success")
結(jié)果:
<class 'django.db.models.query.QuerySet'>
西游記 吳承恩 人民文學(xué)出版社
python3.6 譚浩強(qiáng) 電子工業(yè)出版社
c++ 譚浩強(qiáng) 清華大學(xué)出版社
史記 王五 中華書局
西游記后傳 吳承恩 人民文學(xué)出版社

⑶編輯視圖(使用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")
    """參數(shù)為外鍵名,參數(shù)可以為多個"""
    print(type(books))
    """遍歷QuerySet對象,返回每個數(shù)據(jù)的模型類,進(jìn)而可以使用‘模型類.字段名’獲取某個字段的值"""
    for book in books:
        print(book.name, book.author_a.name,book.publisher_a.name)
    return HttpResponse("success")
結(jié)果:
<class 'django.db.models.query.QuerySet'>
c++ 譚浩強(qiáng) 清華大學(xué)出版社
史記 王五 中華書局
西游記后傳 吳承恩 人民文學(xué)出版社

注:
1、使用常規(guī)方法時:每次在執(zhí)行"book.author_a.name"時,即每次通過圖書去查詢作者時,都會去Author模型類中進(jìn)行一次查詢,這樣的話就會耗性能,特別是有很多數(shù)據(jù)時

2、使用select_related()方法時,在查詢Book模型類數(shù)據(jù)時,通過其方法中的參數(shù)就可以一次性的將關(guān)聯(lián)表中的數(shù)據(jù)查詢出來,后面就直接是獲取Author中的數(shù)據(jù)了而不再需要再次查詢

3、使用for循環(huán)來遍歷QuerySet對象,然后依次返回每個數(shù)據(jù)的模型類,進(jìn)而可以使用"模型類.字段名"來獲取具體某個字段的值

4、只有返回?cái)?shù)據(jù)為一個模型時,才能使用"模型類.字段名"來獲取具體某個字段的值

5、注意:這個例子中是從子表到主表且表關(guān)系為一對多,因此主表中只會有一條數(shù)據(jù),因此可以直接使用"模型類.字段名"來獲取主表中具體某列的值
⑴如果是從主表到子表且表關(guān)系為一對多,因此子表中可能有多條或一條,如果子表數(shù)據(jù)為多條時,那么就需要先使用all()方法獲取全部數(shù)據(jù)(此時為QuerySet對象),然后使用for循環(huán)遍歷,然后才能使用"模型類.字段名"來獲取子表中具體某列的值


prefetch_related()
1、作用:這個方法和select_related()方法類似,就是在訪問多個表中的數(shù)據(jù)的時候,減少查詢的次數(shù)
2、這個方法時為了解決多對一和多對多的關(guān)系的查詢問題。例如要獲取一個作者下的所有文章(一對多關(guān)系中:從主表到子表)
例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():反向關(guān)系,得到Book對象(一個或多個)"""
        for book in author.book_set.all():
            print(book.name)
    return HttpResponse("success")
結(jié)果:
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模型內(nèi)有多條數(shù)據(jù),因此先使用all()方法獲取全部數(shù)據(jù),
        然后再遍歷使用‘模型類名.字段名’來獲取具體某列的值"""
        for book in book.book_set.all():
            print(book.name)
    return HttpResponse("success")
結(jié)果:
<class 'django.db.models.query.QuerySet'>
<class 'app01.models.Author'>
吳承恩 <QuerySet [<Book: Book object (1)>, <Book: Book object (5)>]>
西游記
西游記后傳

注:
使用"模型類名.列名"來獲取某一個列具體的值時:
⑴前提是返回的是一個模型類,而不是一個QuerySet對象。如果是一個QuerySet對象,那么就需要通過for循環(huán)遍歷來依次返回每個具體數(shù)據(jù)的模型類
⑵只有返回的數(shù)據(jù)是一條數(shù)據(jù)的模型類時,才能使用"模型類.字段名"來獲取某一個列具體的值:如一對多中,子表到主表,主表肯定只有一條數(shù)據(jù),那么就可以直接使用"模型類.字段名"來獲取某一個列具體的值
⑶如果返回的是多條數(shù)據(jù)的模型類,那么就必須先使用for循環(huán)來遍歷依次得到每條數(shù)據(jù)的模型類,然后才能使用"模型類.字段名"來獲取某一個列具體的值:如一對多中,主表到子表,子表數(shù)據(jù)可以有一條或多條,當(dāng)為多條時先使用all()來獲取全部數(shù)據(jù),然后遍歷,再使用"模型類.字段名"
⑷其實(shí)不管使用什么方法,只要返回的是多條數(shù)據(jù),那么都需要使用for循環(huán)來依次遍歷出每條數(shù)據(jù),然后才能使用"模型類名.列名"來獲取某一個列具體的值。如果是對多條數(shù)據(jù)使用"模型類名.列名"的話肯定是不行的,都不知道獲取的是哪條數(shù)據(jù)中的列值


defer()
1、作用:在一些表中,可能存在很多字段,但是一些字段的數(shù)據(jù)量可能是比較大的,而此時你又不需要。比如在獲取文章列表的時候,文章的內(nèi)容不是我們所需要的,因此這時候我們就可以使用defer()方法來過濾掉一些字段
2、defer()方法的作用與value()方法有點(diǎn)類似,只不過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,其他字段都查找出來了。當(dāng)然,也可以使用book.price來獲取這個文章的價格,但是會重新執(zhí)行一個查詢語句
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()方法:隨機(jī)選擇一個QuerySet對象

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容