溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Django中QuerySet對(duì)象有什么用

發(fā)布時(shí)間:2021-07-02 10:00:37 來(lái)源:億速云 閱讀:142 作者:小新 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹Django中QuerySet對(duì)象有什么用,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

準(zhǔn)備工作:

新建一個(gè)項(xiàng)目,在項(xiàng)目中新家一個(gè)app,名字自取。將app添加值settings.py中,然后配置settings連接數(shù)據(jù)庫(kù)。

在app中的models中新建模型:

from django.db import models

# Create your models here.
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):
  """圖書(shū)模型"""
  name = models.CharField(max_length=300)
  pages = models.IntegerField()
  price = models.FloatField()  #書(shū)的定價(jià)
  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):
  """圖書(shū)訂單模型"""
  book = models.ForeignKey("Book", on_delete=models.CASCADE)
  price = models.FloatField()   #書(shū)賣出去的真正價(jià)格

  class Meta:
    db_table = 'book_order'

執(zhí)行makemigrations后在migrate。

然后手動(dòng)向表中添加數(shù)據(jù),例如我添加的信息:

Django中QuerySet對(duì)象有什么用

Django中QuerySet對(duì)象有什么用

Django中QuerySet對(duì)象有什么用

Django中QuerySet對(duì)象有什么用

然后配置urls,直至項(xiàng)目運(yùn)行成功。

1.filter:

過(guò)濾,將滿足條件的數(shù)據(jù)提取出來(lái),返回一個(gè)新的QuerySet。

2. exclude:

排除,排除滿足條件的數(shù)據(jù),返回一個(gè)新的QuerySet。

例如,取出book中id大于等于2的圖書(shū),并且id不能等于3的圖書(shū)。示例代碼:

books = models.Book.objects.filter(id__gt=1).exclude(id=3)

我們也可以使用Q表達(dá)式來(lái)實(shí)現(xiàn),

from django.db.models import Q
books = models.Book.objects.filter(id__gt=1).filter(~Q(id=3))

3. annotate:

給QuerySet中的每個(gè)對(duì)象都添加一個(gè)使用查詢表達(dá)式(聚合函數(shù)、F表達(dá)式、Q表達(dá)式、Func表達(dá)式等)的新字段。

例如 給每本圖書(shū)都添加一個(gè)字段叫author_name

from django.db.models import F
books = models.Book.objects.annotate(author_name = F('author__name'))

注意:

Book模型下面最開(kāi)始是沒(méi)有author_name這個(gè)屬性的。只有一個(gè)author屬性連接的一個(gè)外鍵.

author__name是book下的author屬性下的name,即book這個(gè)表通過(guò)外鍵訪問(wèn)到author這個(gè)表中的name值。

執(zhí)行完上述代碼之后就在book中創(chuàng)建了一個(gè)新的屬性author_name,但是只在內(nèi)存中,不會(huì)映射到數(shù)據(jù)庫(kù)中去。

4.order_by:

指定將查詢的結(jié)果根據(jù)某個(gè)字段進(jìn)行排序。如果要倒敘排序,那么可以在這個(gè)字段的前面加一個(gè)負(fù)號(hào)。

示例

def index2(request):
  # 1. 將book中的price屬性按照從小到大進(jìn)行排序
  # books = models.Book.objects.order_by('price')
  # for book in books:
  #   print("%s-%s"%(book.name,book.price))

  # 2. 將book中的price屬性按照從大到小進(jìn)行排序
  books = models.Book.objects.order_by('-price')
  for book in books:
    print("%s-%s"%(book.name,book.price))
  return HttpResponse('success')

修改對(duì)應(yīng)注釋代碼哪呢個(gè)查看到效果。

需求:對(duì)價(jià)格進(jìn)行排序,價(jià)格一樣的就按照頁(yè)數(shù)來(lái)進(jìn)行排序,價(jià)格從小到大,頁(yè)數(shù)從大到小。為了方便查看效果,可以先去數(shù)據(jù)庫(kù)中修改數(shù)據(jù)。

def index2(request):
  # 1. 將book中的price屬性按照從小到大進(jìn)行排序
  # books = models.Book.objects.order_by('price')
  # for book in books:
  #   print("%s-%s"%(book.name,book.price))

  # 2. 將book中的price屬性按照從大到小進(jìn)行排序
  # books = models.Book.objects.order_by('-price')
  # for book in books:
  #   print("%s-%s"%(book.name,book.price))

  # 3. 對(duì)價(jià)格進(jìn)行排序,價(jià)格一樣的就按照頁(yè)數(shù)來(lái)進(jìn)行排序,價(jià)格從小到大,頁(yè)數(shù)從大到小。
  books = models.Book.objects.order_by('price','-pages')
  for book in books:
    print("%s-%s-%s"%(book.name,book.price,book.pages))
  return HttpResponse('success')

注意:

books = models.Book.objects.order_by('price','-pages')不等于books = models.Book.objects.order_by('price').order_by('-pages')

如果使用多個(gè)order_by,會(huì)把前面排序的規(guī)則給打亂,只會(huì)使用最后面的一個(gè)排序方式。

order_by方法并沒(méi)有改變數(shù)據(jù)庫(kù)中的信息位置,只是我們將數(shù)據(jù)取出來(lái)進(jìn)行了排序。

那么如果我們對(duì)數(shù)據(jù)庫(kù)中的信息進(jìn)行了排序,這樣我們就不用每次取數(shù)據(jù)都需要進(jìn)行一次排序了。應(yīng)該怎樣做呢?

我們只需要在模型中添加點(diǎn)代碼就可以了。

例如:我們?cè)贐ook者惡搞模型中對(duì)價(jià)格進(jìn)行排序,價(jià)格一樣的就按照頁(yè)數(shù)來(lái)進(jìn)行排序,價(jià)格從小到大,頁(yè)數(shù)從大到小。

修改Book中的class Meta中的代碼:

  class Meta:
    db_table = 'book_order'
    ordering = ['price','-pages']


這樣就對(duì)數(shù)據(jù)庫(kù)中的信息進(jìn)行了排序,我們?cè)谌?shù)據(jù) 的時(shí)候也不用使用order_by來(lái)進(jìn)行排序了。但是這樣需要重新makegrations和migrate一下,這里就不做演示了。

需求:根據(jù)每本圖書(shū)的銷量來(lái)進(jìn)行排序

from django.db.models import Q,F,Count

def index2(request):

  # 1. 將book中的price屬性按照從小到大進(jìn)行排序
  # books = models.Book.objects.order_by('price')
  # for book in books:
  #   print("%s-%s"%(book.name,book.price))

  # 2. 將book中的price屬性按照從大到小進(jìn)行排序
  # books = models.Book.objects.order_by('-price')
  # for book in books:
  #   print("%s-%s"%(book.name,book.price))

  # 3. 對(duì)價(jià)格進(jìn)行排序,價(jià)格一樣的就按照頁(yè)數(shù)來(lái)進(jìn)行排序,價(jià)格從小到大,頁(yè)數(shù)從大到小。
  # books = models.Book.objects.order_by('price','-pages')
  # for book in books:
  #   print("%s-%s-%s"%(book.name,book.price,book.pages))

  # 4. 根據(jù)每本圖書(shū)的銷量來(lái)進(jìn)行排序
  results = models.Book.objects.annotate(sale_num=Count('bookorder__id')).order_by('sale_num')
  for result in results:
    print("%s-%s"%(result.name,result.sale_num))
  return HttpResponse('success')

因?yàn)锽ook這個(gè)模型中沒(méi)有sale_num這個(gè)屬性,所以我們需要使用annotate這個(gè)方法來(lái)創(chuàng)建一個(gè)sale_num屬性,然后使用Count方法進(jìn)行賦值,然后使用order_by 進(jìn)行排序。就實(shí)現(xiàn)了這個(gè)需求。

5. values:

用來(lái)指定在提取數(shù)據(jù)出來(lái),需要提取哪些字段。默認(rèn)情況下會(huì)把表中所有的字段全部都提取出來(lái),可以使用values來(lái)進(jìn)行指定,并且使用了values方法后,提取出的QuerySet中的數(shù)據(jù)類型不是模型,而是在values方法中指定的字段和值形成的字典。

需求: 只需要提取Book中的id 和 name

示例:

def index3(request):

  # 1. 只需要提取Book中的id 和 name
  books = models.Book.objects.values('id','name')
  for book in books:
    print(book)
  return HttpResponse('success')

注意: 返回的是一個(gè)字典類型。字典的key就是屬性名,value是屬性值。

需求:提取Book中的name和author__name,并且字典中的key自己指定,不使用默認(rèn)的。字典的key分別為bookName和authorNmae

def index3(request):

  # 1. 只需要提取Book中的id 和 name
  # books = models.Book.objects.values('id','name')
  # for book in books:
  #   print(book)

  # 需求:提取Book中的name和author__name,并且字典中的key自己指定,不使用默認(rèn)的。
  # 字典的key分別為`bookName`和`authorNmae`
  books = models.Book.objects.values(bookName=F('name'),authorName=F('author__name'))
  for book in books:
    print(book)
  return HttpResponse('success')

注意:

自己取名字不能取該模型的屬性名,否則會(huì)報(bào)錯(cuò)。

如果在value中不傳遞任何參數(shù),那么會(huì)獲取這個(gè)模型所有的值。返回的還是一個(gè)字典。

6:values_list:

類似于values。只不過(guò)返回的QuerySet中,存儲(chǔ)的不是字典,而是元組。操作和values是一樣的,只是返回類型不一樣。

注意: 當(dāng)我們使用此方法只返回一個(gè)值的時(shí)候,那么這個(gè)元祖中只有一個(gè)值,我們可以添加一個(gè)參數(shù)flat=True,將元祖去掉,從而得到一個(gè)字符竄。只有當(dāng)values_list中只有一個(gè)值的時(shí)候才能使用這個(gè)方法:

示例:

books = models.Book.objects.values_list('name',flat=True)

7. all:

獲取這個(gè)ORM模型的QuerySet對(duì)象。即獲取所有的數(shù)據(jù)。

獲取Book中所有數(shù)據(jù)

示例:

books = models.Book.objects.all()

8.select_related:

在提取某個(gè)模型的數(shù)據(jù)的同時(shí),也提前將相關(guān)聯(lián)的數(shù)據(jù)提取出來(lái)。比如提取文章數(shù)據(jù),可以使用select_related將author信息提取出來(lái),以后再次使用article.author的時(shí)候就不需要再次去訪問(wèn)數(shù)據(jù)庫(kù)了??梢詼p少數(shù)據(jù)庫(kù)查詢的次數(shù)。

def index4(request):
  books = models.Book.objects.select_related('author')
  for book in books:
    print(book.author.name)
  return HttpResponse('succrss')

注意: select_related只能使用在設(shè)置了外鍵的模型中(即只能在一對(duì)多模型上,不能多對(duì)一,多對(duì)多等),比如我們只在Book設(shè)置了author外鍵和publisher外鍵。那么select_related里面只能傳如這兩個(gè)參數(shù),而不能傳入別的參數(shù),如BookOrder,因?yàn)槲覀兪窃贐ookOrder中設(shè)置的外鍵連接到Book,并沒(méi)有在Book中設(shè)置外鍵連接到BookOrder這個(gè)模型。

9. prefetch_related:

這個(gè)方法和select_related非常的類似,就是在訪問(wèn)多個(gè)表中的數(shù)據(jù)的時(shí)候,減少查詢的次數(shù)。這個(gè)方法是為了解決多對(duì)一和多對(duì)多的關(guān)系的查詢問(wèn)題。

需求:從book中通過(guò)prefetch_related查詢BookOrder中的信息。

示例代碼

def index5(request):
  books = models.Book.objects.prefetch_related("bookorder_set")
  for book in books:
    print('*'*30)
    print(book.name)
    orders = book.bookorder_set.all()
    for order in orders:
      print(order.id)
  return HttpResponse('success')

prefetch_related方法也能辦到select_related方法能辦到的事情,只是select_related方法效率比prefetch_related方法效率高一點(diǎn)。所以能使用select_related方法的話就是用這個(gè)方法。但是這兩種方法的執(zhí)行效率都比傳統(tǒng)的方法執(zhí)行效率高。傳統(tǒng)的方法就是先返回book對(duì)象,再通過(guò)book去查詢對(duì)應(yīng)的外鍵的相關(guān)信息。

10. defer:

在一些表中,可能存在很多的字段,但是一些字段的數(shù)據(jù)量可能是比較龐大的,而此時(shí)你又不需要,比如我們?cè)讷@取文章列表的時(shí)候,文章的內(nèi)容我們是不需要的,因此這時(shí)候我們就可以使用defer來(lái)過(guò)濾掉一些字段。這個(gè)字段跟values有點(diǎn)類似,只不過(guò)defer返回的不是字典,而是模型。

需求:過(guò)濾掉book 的name字段

def index6(request):
  # 過(guò)濾掉book的name字段
  books = models.Book.objects.defer('name')
  for book in books:
    print(book.id)

  return HttpResponse('sucdess')

注意: 我們?cè)谑褂胐efer過(guò)濾掉name字段之后,我們還是可以訪問(wèn)到name屬性,是因?yàn)楫?dāng)我們?cè)L問(wèn)name屬性的時(shí)候,Django又去執(zhí)行了一遍sql語(yǔ)句查詢的代碼。所以在我們開(kāi)發(fā)的過(guò)程中,除非我們確定不會(huì)使用到此屬性,否則不要去過(guò)濾它。

defer雖然能過(guò)濾字段,但是有些字段是不能過(guò)濾的,比如id,即使你過(guò)濾了,也會(huì)提取出來(lái)。

11. only:

跟defer類似,只不過(guò)defer是過(guò)濾掉指定的字段,而only是只提取指定的字段。

需求:只提取name屬性

  # 只提取name屬性
  books = models.Book.objects.only('name')
  for book in books:
    print(book.id,book.name)

注意: id這個(gè)字段我們是不能操作的,像上面一樣,我們沒(méi)有提取id屬性,但是還是給我們提取出來(lái)了。所以id屬性是一定會(huì)被提取出來(lái)的。

和defer一樣,就算我們沒(méi)有提取某個(gè)屬性出來(lái),我們還是可以訪問(wèn)到的,只是會(huì)重新執(zhí)行一遍sql代碼而已。

12. get:

獲取滿足條件的數(shù)據(jù)。這個(gè)函數(shù)只能返回一條數(shù)據(jù),并且如果給的條件有多條數(shù)據(jù),那么這個(gè)方法會(huì)拋出MultipleObjectsReturned錯(cuò)誤,如果給的條件沒(méi)有任何數(shù)據(jù),那么就會(huì)拋出DoesNotExit錯(cuò)誤。所以這個(gè)方法在獲取數(shù)據(jù)的只能,只能有且只有一條。

# 獲取id為1的數(shù)據(jù)
book = models.Book.objects.get(id=1)

13. create:

創(chuàng)建一條數(shù)據(jù),并且保存到數(shù)據(jù)庫(kù)中。這個(gè)方法相當(dāng)于先用指定的模型創(chuàng)建一個(gè)對(duì)象,然后再調(diào)用這個(gè)對(duì)象的save方法。

publusher = models.Publisher.objects.create(name='知了出版社')

14. get_or_create:


根據(jù)某個(gè)條件進(jìn)行查找,如果找到了那么就返回這條數(shù)據(jù),如果沒(méi)有查找到,那么就創(chuàng)建一個(gè)。

result = models.Publisher.objects.get_or_create(name='知了出版社')
print(result)

會(huì)返回一個(gè)元祖

查找的對(duì)象以及是否創(chuàng)建了這條數(shù)據(jù)。False就是沒(méi)有創(chuàng)建這條數(shù)據(jù)。

15. bulk_create:

和create方法類似,只是這個(gè)方法可以一次性創(chuàng)建多個(gè)數(shù)據(jù)。

publusher = models.Publisher.objects.bulk_create([models.Publisher(name='123出版社'),
models.Publisher(name='abc出版社'),])

16. count:

獲取提取的數(shù)據(jù)的個(gè)數(shù)。如果想要知道總共有多少條數(shù)據(jù),那么建議使用count,而不是使用len(articles)這種。因?yàn)閏ount在底層是使用select count(*)來(lái)實(shí)現(xiàn)的,這種方式比使用len函數(shù)更加的高效。

count = models.Book.objects.filter(name='xxx').count()

17. first和last:

返回QuerySet中的第一條和最后一條數(shù)據(jù)。如果為空則返回none。

18. aggregate:

使用聚合函數(shù)。

19. exists:

判斷某個(gè)條件的數(shù)據(jù)是否存在。如果要判斷某個(gè)條件的元素是否存在,那么建議使用exists,這比使用count或者直接判斷QuerySet更有效得多。

示例代碼如下:

# 最高效的判斷值是否存在的方法
if Article.objects.filter(name='三國(guó)演義').exists():
  print(True)
# 比上面的方法效率低一點(diǎn)
if Article.objects.filter(name='三國(guó)演義').count() > 0:
  print(True)
# 還要比上面的效率低
if Article.objects.filter(name='三國(guó)演義'):
  print(True)

20. distinct:

去除掉那些重復(fù)的數(shù)據(jù)。這個(gè)方法如果底層數(shù)據(jù)庫(kù)用的是MySQL,那么不能傳遞任何的參數(shù)。

需求:提取所有銷售的價(jià)格超過(guò)80元的圖書(shū),并且刪掉那些重復(fù)的,那么可以使用distinct來(lái)幫我們實(shí)現(xiàn),示例代碼如下:

  books = models.Book.objects.filter(bookorder__price__gte=80).distinct()
  for book in books:
    print(book.name)

并且distinct只會(huì)剔除那些完全相同的數(shù)據(jù),如果有一個(gè)字段不相同,都不會(huì)剔除的。

如果在distinct之前使用了order_by,那么因?yàn)閛rder_by會(huì)提取order_by中指定的字段,因此再使用distinct就會(huì)根據(jù)多個(gè)字段來(lái)進(jìn)行唯一化,所以就不會(huì)把那些重復(fù)的數(shù)據(jù)刪掉。

示例:

orders = models.BookOrder.objects.order_by("pages").values("book_id").distinct()

21. update:

執(zhí)行更新操作,在SQL底層走的也是update命令。比如要將所有圖書(shū)的價(jià)格都提高10元。

book = models.Book.objects.update(price=F('price')+5)

22. delete:

刪除所有滿足條件的數(shù)據(jù)。刪除數(shù)據(jù)的時(shí)候,要注意on_delete指定的處理方式。

例如刪除作者id大于等于3的數(shù)據(jù)

result = models.Author.objects.get(id__gte=4).delete()

刪除數(shù)據(jù)時(shí)一定要對(duì)你的表了如指掌,因?yàn)榭赡軙?huì)牽連到很多其他數(shù)據(jù)。像在這個(gè)地方將這個(gè)作者刪除了之后,那么這個(gè)作者對(duì)應(yīng)的圖書(shū)也將會(huì)被刪除。

23. 切片操作:

有時(shí)候我們查找數(shù)據(jù),有可能只需要其中的一部分。那么這時(shí)候可以使用切片操作來(lái)幫我們完成。QuerySet使用切片操作就跟列表使用切片操作是一樣的。

  # 獲取1,2兩條數(shù)據(jù)
  books = models.Book.objects.all()[1:3]
  for book in books:
    print(book)

以上是“Django中QuerySet對(duì)象有什么用”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI