Django基礎(5) ----基於雙下劃線的跨表查詢,聚合查詢,分組查詢,F查詢,Q查詢

1、基於雙下劃線的跨表查詢

Django 還提供了一種直觀而高效的方式在查詢(lookups)中表示關聯關係,它能自動確認 SQL JOIN 聯繫。要作跨關係查詢,就使用兩個下劃線來連接模型(model)間關聯字段的名稱,直到最終連接到你想要的model 爲止。python

核心得學會通知ORM引擎何時,join哪張表mysql

join看似複雜,實則最簡單。由於把字段列出來以後,就至關於單表操做了!想怎麼取值均可以!git

正向查詢按字段,反向查詢按表名小寫用來告訴ORM引擎join哪張表sql

返回值是QuerySet數據庫

一對多:

正向查詢

返回結構是queryset()django

正向查詢:關聯屬性在book表中,因此book對象找關聯出版社對象,正向查詢
反向查詢:關聯屬性在book表中,因此publish對象找關聯書籍,反向查詢編程

       按字段:xx
book  ------------------ >  publish
      <--------------------
      按表名小寫__字段名。好比publish__name

舉例:查詢西遊記這本書的出版社名字

先使用原生sql查詢app

SELECT app01_publish.name from app01_book
INNER JOIN app01_publish on 
app01_book.publish_id = app01_publish.id
WHERE app01_book.title = '西遊記'
View Code

執行結果爲:榴蓮出版社ide

它的步驟爲:先連表,再過濾函數

 

使用orm引擎查詢

修改settings.py,最後一行添加。表示開啓日誌

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME':'fy', # 要鏈接的數據庫,鏈接前須要建立好
        'USER':'root', # 鏈接數據庫的用戶名
        'PASSWORD':'123', # 鏈接數據庫的密碼
        'HOST':'127.0.0.1',# 鏈接主機,默認本級
        'PORT':3306 #  端口 默認3306
    }
}
View Code

修改urls.py,增長路徑query

urlpatterns = [
    path('admin/', admin.site.urls),
    path('add/', views.add),
    path('query/', views.query),
]
View Code

修改views.py,增長query視圖函數

def query(request):
    ret = Book.objects.filter(title='西遊記').values("publish__name")
    print(ret)
View Code

解釋:

Book.objects 表示基礎表,它是鏈式編程的開始。

publish__name 表示publish表下的name字段。由於要的name字段,它不在Book表中。那麼指定外部表示,須要加雙下劃線。注意:此表必需要和Book表有關聯!

 

訪問url:http://127.0.0.1:8000/query/

查看Pycharm控制檯,輸出:

<QuerySet [{'publish__name': '榴蓮出版社'}]>
(0.000) SELECT "app01_publish"."name" FROM "app01_book" INNER JOIN "app01_publish" ON ("app01_book"."publish_id" = "app01_publish"."id") WHERE "app01_book"."title" = '西遊記' LIMIT 21; args=('西遊記',)
View Code

 

能夠看出,ORM執行的sql和手寫的sql,大體是同樣的!

 

反向查詢

舉例:查詢出版過西遊記的出版社

def query(request):
    ret = Publish.objects.filter(book__title="西遊記").values("name")
    print(ret)

    return HttpResponse('查詢成功')
View Code

解釋:

book__title 表示book表中的title字段,它不須要加引號

values("name") 表示publish表的中name字段,爲何呢?由於基礎表示publish,它能夠直接取name字段!

 

刷新頁面,查看控制檯輸出:

(0.001) SELECT "app01_publish"."name" FROM "app01_publish" INNER JOIN "app01_book" ON ("app01_publish"."id" = "app01_book"."publish_id") WHERE "app01_book"."title" = '西遊記' LIMIT 21; args=('西遊記',)
<QuerySet [{'name': '榴蓮出版社'}]>
View Code

查詢結果上面的例子是同樣的。

 

多對多查詢

正向查詢:關聯屬性在book表中,因此book對象找關聯做者集合,正向查詢
反向查詢:關聯屬性在book表中,因此author對象找關聯書籍,反向查詢

      正 按字段:xx
book  ------------------------- >  author
      <-------------------------
      反 按表名小寫__字段名

正向查詢

舉例:查詢西遊記這本書籍的全部做者的姓名和年齡

先用原生sql查詢

SELECT app01_author.name,app01_author.age from app01_book
INNER JOIN app01_book_authors on 
app01_book_authors.book_id = app01_book.id INNER JOIN app01_author on
app01_book_authors.author_id = app01_author.id
WHERE app01_book.title = '西遊記'
View Code

涉及到3表查詢,查詢結果爲:

 

使用orm引擎查詢

def query(request):
    ret = Book.objects.filter(title="西遊記").values("authors__name","authors__age")
    print(ret)

    return HttpResponse('查詢成功')
View Code

刷新頁面,查看控制檯輸出:

<QuerySet [{'authors__name': 'xiao', 'authors__age': 25}]>
(0.001) SELECT "app01_author"."name", "app01_author"."age" FROM "app01_book" LEFT OUTER JOIN "app01_book_authors" ON ("app01_book"."id" = "app01_book_authors"."book_id") LEFT OUTER JOIN "app01_author" ON ("app01_book_authors"."author_id" = "app01_author"."id") WHERE "app01_book"."title" = '西遊記' LIMIT 21; args=('西遊記',)
View Code

 解釋:

因爲book表和author表是多對多關係,因此使用ORM查詢時,它會自動對應關係

authors__name 表示author表的name字段

那麼使用ORM處理多表,就顯得很簡單了!

反向查詢

仍是上面的需求,以author爲基礎表查詢

def query(request):
    ret = Author.objects.filter(book__title="西遊記").values("name","age")
    print(ret)

    return HttpResponse('查詢成功')
View Code

刷新頁面,查看控制檯輸出:

<QuerySet [{'name': 'xiao', 'age': 25}]>
(0.002) SELECT "app01_author"."name", "app01_author"."age" FROM "app01_author" INNER JOIN "app01_book_authors" ON ("app01_author"."id" = "app01_book_authors"."author_id") INNER JOIN "app01_book" ON ("app01_book_authors"."book_id" = "app01_book"."id") WHERE "app01_book"."title" = '西遊記' LIMIT 21; args=('西遊記',)
View Code

執行結果同上!

一對一

正向查詢:關聯屬性在authordetail表中,因此author對象找關聯做者詳情,正向查詢
反向查詢:關聯屬性在author表中,因此authordetail對象找關聯做者信息,反向查詢

        正向: 按字段:.ad
author  ------------------------- >  authordetail
      <-------------------------
        反向: 按表名小寫  authordetail_obj.author

正向查詢

舉例:查詢xiao的女友名字

def query(request):
    ret = Author.objects.filter(name="xiao").values("ad__gf")
    print(ret)

    return HttpResponse('查詢成功')
View Code

解釋:ORM查詢時,會自動對應關係。ad__gf表示authordetail表的gf字段

刷新頁面,查看控制檯輸出:

<QuerySet [{'ad__gf': '趙麗穎'}]>
(0.001) SELECT "app01_authordetail"."gf" FROM "app01_author" INNER JOIN "app01_authordetail" ON ("app01_author"."ad_id" = "app01_authordetail"."id") WHERE "app01_author"."name" = 'xiao' LIMIT 21; args=('xiao',)
View Code

反向查詢

仍是上面的需求,以authordetail表爲基礎表查詢

def query(request):
    ret = AuthorDetail.objects.filter(author__name="xiao").values("gf")
    print(ret)

    return HttpResponse('查詢成功')
View Code

刷新頁面,查看控制檯輸出:

<QuerySet [{'gf': '趙麗穎'}]>
(0.002) SELECT "app01_authordetail"."gf" FROM "app01_authordetail" INNER JOIN "app01_author" ON ("app01_authordetail"."id" = "app01_author"."ad_id") WHERE "app01_author"."name" = 'xiao' LIMIT 21; args=('xiao',)
View Code

進階練習(連續跨表)

舉例1

查詢榴蓮出版社出版過的全部書籍的名字以及做者的姓名

正向查詢

def query(request):
    ret = Book.objects.filter(publish__name="榴蓮出版社").values_list("title","authors__name")
    print(ret)

    return HttpResponse('查詢成功')
View Code

解釋:

book表示鏈接出版社和做者的核心表。以它爲基礎表查詢,比較好處理!

publish__name 表示publish表的name字段。

authors__name表示book_authors表(book和author的關係表)的name字段。

刷新頁面,查看控制檯輸出:

<QuerySet [('西遊記', 'xiao')]>
(0.000) SELECT "app01_book"."title", "app01_author"."name" FROM "app01_book" INNER JOIN "app01_publish" ON ("app01_book"."publish_id" = "app01_publish"."id") LEFT OUTER JOIN "app01_book_authors" ON ("app01_book"."id" = "app01_book_authors"."book_id") LEFT OUTER JOIN "app01_author" ON ("app01_book_authors"."author_id" = "app01_author"."id") WHERE "app01_publish"."name" = '榴蓮出版社' LIMIT 21; args=('榴蓮出版社',)
View Code

反向查詢

仍是上面的需求,以publish表爲基礎表查詢

def query(request):
    ret = Publish.objects.filter(name="榴蓮出版社").values_list("book__title","book__authors__age","book__authors__name")
    print(ret)

    return HttpResponse('查詢成功')
View Code

刷新頁面,查看控制檯輸出:

<QuerySet [('西遊記', 25, 'xiao')]>
(0.001) SELECT "app01_book"."title", "app01_author"."age", "app01_author"."name" FROM "app01_publish" LEFT OUTER JOIN "app01_book" ON ("app01_publish"."id" = "app01_book"."publish_id") LEFT OUTER JOIN "app01_book_authors" ON ("app01_book"."id" = "app01_book_authors"."book_id") LEFT OUTER JOIN "app01_author" ON ("app01_book_authors"."author_id" = "app01_author"."id") WHERE "app01_publish"."name" = '榴蓮出版社' LIMIT 21; args=('榴蓮出版社',)
View Code

舉例2

手機號以11開頭的做者出版過的全部書籍名稱以及出版社名稱

提示:涉及到5表查詢!

先使用原生sql查詢

SELECT app01_book.title,a01p.name from app01_book 
INNER JOIN app01_book_authors as a
on app01_book.id = a.book_id
INNER JOIN app01_author as a3
on a.author_id = a3.id
INNER JOIN app01_authordetail as a2
on a3.ad_id = a2.id
INNER JOIN app01_publish as a01p 
on app01_book.publish_id = a01p.id
WHERE a2.tel like '11%'
View Code

執行結果:

 

使用orm引擎查詢

 正向查詢:

def query(request):
    ret = Book.objects.filter(authors__ad__tel__startswith="11").values("title","publish__name")
    print(ret)

    return HttpResponse('查詢成功')
View Code

解釋:

authors__ad__tel 表示book_authors表,author表的ad字段,authordetail表的tel字段,作關聯查詢。

__startswith 表示以什麼開頭,它會使用like查詢,好比'11%'

"title","publish__name" 分別表示book表的title字段,publish表的name字段

 

刷新頁面,查看控制檯輸出:

<QuerySet [{'title': 'python', 'publish__name': '西瓜出版社'}, {'title': 'python', 'publish__name': '西瓜出版社'}, {'title': 'python', 'publish__name': '西瓜出版社'}, {'title': '西遊記', 'publish__name': '榴蓮出版社'}, {'title': '三國演義', 'publish__name': '西瓜出版社'}]>
(0.001) SELECT "app01_book"."title", "app01_publish"."name" FROM "app01_book" INNER JOIN "app01_book_authors" ON ("app01_book"."id" = "app01_book_authors"."book_id") INNER JOIN "app01_author" ON ("app01_book_authors"."author_id" = "app01_author"."id") INNER JOIN "app01_authordetail" ON ("app01_author"."ad_id" = "app01_authordetail"."id") INNER JOIN "app01_publish" ON ("app01_book"."publish_id" = "app01_publish"."id") WHERE "app01_authordetail"."tel" LIKE '11%' ESCAPE '\' LIMIT 21; args=('11%',)
View Code

反向查詢:

def query(request):
    ret = Author.objects.filter(ad__tel__startswith="11").values("book__title","book__publish__name")
    print(ret)

    return HttpResponse('查詢成功')
View Code

刷新頁面,查看控制檯輸出:

<QuerySet [{'book__publish__name': '西瓜出版社', 'book__title': 'python'}, {'book__publish__name': '榴蓮出版社', 'book__title': '西遊記'}, {'book__publish__name': '西瓜出版社', 'book__title': 'python'}, {'book__publish__name': '西瓜出版社', 'book__title': '三國演義'}, {'book__publish__name': '西瓜出版社', 'book__title': 'python'}]>
(0.001) SELECT "app01_book"."title", "app01_publish"."name" FROM "app01_author" INNER JOIN "app01_authordetail" ON ("app01_author"."ad_id" = "app01_authordetail"."id") LEFT OUTER JOIN "app01_book_authors" ON ("app01_author"."id" = "app01_book_authors"."author_id") LEFT OUTER JOIN "app01_book" ON ("app01_book_authors"."book_id" = "app01_book"."id") LEFT OUTER JOIN "app01_publish" ON ("app01_book"."publish_id" = "app01_publish"."id") WHERE "app01_authordetail"."tel" LIKE '11%' ESCAPE '\' LIMIT 21; args=('11%',)
View Code

2、聚合查詢

聚合 是aggreate(*args,**kwargs),經過QuerySet 進行計算。作求值運算的時候使用

主要有Sum,Avg,Max,Min。使用前,須要導入模塊

from django.db.models import Sum,Avg,Max,Min,Count

Sum (總和)

返回值是一個字典

舉例:查詢全部書籍的總價格

def query(request):
    ret = Book.objects.all().aggregate(Sum("price"))
    print(ret)

    return HttpResponse('查詢成功')
View Code

刷新頁面,查看控制檯輸出:

{'price__sum': Decimal('522.00')}
(0.001) SELECT CAST(SUM("app01_book"."price") AS NUMERIC) AS "price__sum" FROM "app01_book"; args=()
[02/Jul/2018 21:45:26] "GET /query/ HTTP/1.1" 200 12
View Code

Avg (平均值)

返回值是一個字典

舉例:查詢全部書籍的平均價格

使用原生sql查詢

select avg(price) from app01_book

執行輸出:174

使用orm引擎查詢

def query(request):
    ret = Book.objects.all().aggregate(Avg("price"))
    print(ret)

    return HttpResponse('查詢成功')
View Code

刷新頁面,查看控制檯輸出:

(0.001) SELECT AVG("app01_book"."price") AS "price__avg" FROM "app01_book"; args=()
[02/Jul/2018 21:38:42] "GET /query/ HTTP/1.1" 200 12
{'price__avg': 174.0}
View Code

aggregate()是QuerySet 的一個終止子句,意思是說,它返回一個包含一些鍵值對的字典。鍵的名稱是聚合值的標識符,值是計算出來的聚合值。鍵的名稱是按照字段和聚合函數的名稱自動生成出來的。若是你想要爲聚合值指定一個名稱,能夠向聚合子句提供它。

對返回的key起別名

def query(request):
    ret = Book.objects.all().aggregate(avg = Avg("price"))
    print(ret)

    return HttpResponse('查詢成功')
View Code

刷新頁面,查看控制檯輸出:

{'avg': 174.0}
(0.001) SELECT AVG("app01_book"."price") AS "avg" FROM "app01_book";args=()
View Code

Count (統計結果行數)

舉例:查詢西瓜出版社總共出版過多少本書籍

def query(request):
    ret = Book.objects.all().aggregate(count = Count("id"))
    print(ret)

    return HttpResponse('查詢成功')
View Code

刷新頁面,查看控制檯輸出:

{'count': 3}
(0.001) SELECT COUNT("app01_book"."id") AS "count"  FROM "app01_book"; args=()
View Code

 

3、分組查詢

分組:將查詢結果按照某個字段或多個字段進行分組。字段中值相等的爲一組!

annotate()爲調用的QuerySet中每個對象都生成一個獨立的統計值(統計方法用聚合函數)。

單表查詢

修改models.py,增長一個模型表

class Emp(models.Model):
    name=models.CharField(max_length=32)
    age=models.IntegerField()
    salary=models.DecimalField(max_digits=8,decimal_places=2)
    dep=models.CharField(max_length=32)
    province=models.CharField(max_length=32)
View Code

使用2個命令生成表

python manage.py makemigrations
python manage.py migrate

使用sql插入3條數據,注意修改應用名

INSERT INTO `app01_emp` (`id`, `name`, `age`, `salary`, `dep`, `province`) VALUES (1, 'zhang', 26, 4000, '保潔部', '山東省');
INSERT INTO `app01_emp` (`id`, `name`, `age`, `salary`, `dep`, `province`) VALUES (2, 'li', 25, 3500, '保潔部', '北京');
INSERT INTO `app01_emp` (`id`, `name`, `age`, `salary`, `dep`, `province`) VALUES (3, 'wang', 27, 5000, '公關部', '北京');
View Code

舉例1:查詢每個部門的平均薪水

使用原生sql查詢

select dep,avg(salary) from app01_emp GROUP BY dep

使用orm引擎查詢

導入emp表

from app01.models import Book,Publish,Author,AuthorDetail,Emp

修改視圖函數

<QuerySet [{'dep': '保潔部', 'avg_salary': 3750.0}, {'dep': '公關部', 'avg_salary': 5000.0}]>
(0.000) SELECT "app01_emp"."dep", AVG("app01_emp"."salary") AS "avg_salary" FROM "app01_emp" GROUP BY "app01_emp"."dep" LIMIT 21;args=()
View Code

解釋:

values("dep") 表示以dep字段進行分組

avg_salary 表示爲字段起別名

Avg("salary") 表示取平均數

 

刷新頁面,查看控制檯輸出:

<QuerySet [{'salary__avg': 3750.0, 'dep': '保潔部'}, {'salary__avg': 5000.0, 'dep': '公關部'}]>
(0.001) SELECT "app01_emp"."dep", AVG("app01_emp"."salary") AS "salary__avg" FROM "app01_emp" GROUP BY "app01_emp"."dep" LIMIT 21;  args=()
View Code

舉例2:查詢每個省/直轄市對應的人數

def query(request):
    ret = Emp.objects.values("province").annotate(Count("id"))
    print(ret)

    return HttpResponse('查詢成功')
View Code

刷新頁面,查看控制檯輸出:

<QuerySet [{'id__count': 2, 'province': '北京'}, {'id__count': 1, 'province': '山東省'}]>
(0.002) SELECT "app01_emp"."province", COUNT("app01_emp"."id") AS "id__count" FROM "app01_emp" GROUP BY "app01_emp"."province" LIMIT 21; args=()
View Code

總結:

單表.objects.values('group by 字段').annotate(統計字段)

 

多表查詢

舉例1:查詢每個出版社的名稱,以及對應書籍的平均價格

使用原生sql查詢

select app01_publish.name,avg(app01_book.price) from app01_book INNER JOIN app01_publish ON 
app01_publish.id = app01_book.publish_id
GROUP BY app01_publish.id
View Code

查詢結果:

 

使用orm引擎查詢

def query(request):
    ret = Publish.objects.values("id").annotate(avg=Avg("book__price")).values("name","avg")
    print(ret)

    return HttpResponse('查詢成功')
View Code

解釋:

values("id") 以id字段進行分組

avg=Avg("book__price") 表示將關聯的book表的price字段,計算平均數。avg表示起別名

values("name","avg") 取出name和avg字段

 

刷新頁面,查看控制檯輸出:

<QuerySet [{'name': '西瓜出版社', 'avg': 211.0}, {'name': '榴蓮出版社', 'avg': 100.0}]>
(0.000) SELECT "app01_publish"."name", AVG("app01_book"."price") AS "avg" FROM "app01_publish" LEFT OUTER JOIN "app01_book" ON ("app01_publish"."id" = "app01_book"."publish_id") GROUP BY "app01_publish"."id", "app01_publish"."name" LIMIT 21; args=()
View Code

舉例2:查詢每一本書籍的名稱以及做者個數

def query(request):
    ret = Book.objects.values("id").annotate(count=Count("authors__name")).values("title","count")
    print(ret)

    return HttpResponse('查詢成功')
View Code

刷新頁面,查看控制檯輸出:

<QuerySet [{'title': 'python', 'count': 3}, {'title': '三國演義', 'count': 1}, {'title': '西遊記', 'count': 1}]>
(0.001) SELECT "app01_book"."title", COUNT("app01_author"."name") AS "count" FROM "app01_book" LEFT OUTER JOIN "app01_book_authors" ON ("app01_book"."id" = "app01_book_authors"."book_id") LEFT OUTER JOIN "app01_author" ON ("app01_book_authors"."author_id" = "app01_author"."id") GROUP BY "app01_book"."id", "app01_book"."title" LIMIT 21; args=()
View Code

舉例3:查詢大於一個做者的書籍名稱

def query(request):
    ret = Book.objects.values("id").annotate(count=Count("authors__name")).filter(count__gt=1).values("title","count")
    print(ret)

    return HttpResponse('查詢成功')
View Code

刷新頁面,查看控制檯輸出:

<QuerySet [{'title': 'python', 'count': 3}]>
(0.001) SELECT "app01_book"."title", COUNT("app01_author"."name") AS "count" FROM "app01_book" LEFT OUTER JOIN "app01_book_authors" ON ("app01_book"."id" = "app01_book_authors"."book_id") LEFT OUTER JOIN "app01_author" ON ("app01_book_authors"."author_id" = "app01_author"."id") GROUP BY "app01_book"."id", "app01_book"."title" HAVING COUNT("app01_author"."name") > 1 LIMIT 21;
View Code

注意:它使用了HAVING

 

總結:

跨表分組查詢本質就是將關聯表join成一張表,再按單表的思路進行分組查詢。

1 肯定是不是多表分組
2 若是是多表分組,肯定分組條件(group by哪個字段)
3 語法:
     每個後跟的表A.objects.values("id").annotate("統計函數(與A表關聯的B表下的某個字段)")

 

查詢練習

舉例1:統計每個出版社的最便宜書籍的價格

def query(request):
    ret = Publish.objects.annotate(MinPrice=Min("book__price")).values_list("name","MinPrice")
    print(ret)

    return HttpResponse('查詢成功')
View Code

刷新頁面,查看控制檯輸出:

<QuerySet [('西瓜出版社', Decimal('122.00')), ('榴蓮出版社', Decimal('100.00'))]>
(0.001) SELECT "app01_publish"."name", CAST(MIN("app01_book"."price") AS NUMERIC) AS "MinPrice" FROM "app01_publish" LEFT OUTER JOIN "app01_book" ON ("app01_publish"."id" = "app01_book"."publish_id") GROUP BY "app01_publish"."id", "app01_publish"."name", "app01_publish"."email", "app01_publish"."addr"  LIMIT 21; args=()
View Code

舉例2:統計每一本書的做者個數

def query(request):
    ret = Book.objects.annotate(authorsNum=Count('authors__name')).values()
    print(ret)

    return HttpResponse('查詢成功')
View Code

舉例3:統計每一本以py開頭的書籍的做者個數

def query(request):
    ret = Book.objects.filter(title__startswith="Py").annotate(num_authors=Count('authors'))
    print(ret)

    return HttpResponse('查詢成功')
View Code

舉例4:根據一本圖書做者數量的多少對查詢集QuerySet進行排序

def query(request):
    ret = Book.objects.annotate(num_authors=Count('authors')).order_by('num_authors').values()
    print(ret)

    return HttpResponse('查詢成功')
View Code

舉例5:查詢各個做者出的書的總價格

def query(request):
    ret = Author.objects.annotate(SumPrice=Sum("book__price")).values("name","SumPrice")
    print(ret)

    return HttpResponse('查詢成功')
View Code

4、F查詢

F() 專門取對象中某列值的操做

F()容許Django在未實際連接數據的狀況下具備對數據庫字段的值的引用。一般狀況下咱們在更新數據時須要先從數據庫裏將原數據取出後方在內存裏,而後編輯某些屬性,最後提交。

 

在上面全部的例子中,咱們構造的過濾器都只是將字段值與某個常量作比較。若是咱們要對兩個字段的值作比較,那該怎麼作呢?

Django 提供 F() 來作這樣的比較。F() 的實例能夠在查詢中引用字段,來比較同一個 model 實例中兩個不一樣字段的值。

修改models.py,增長3個字段

class Book(models.Model):
    title=models.CharField(max_length=32,unique=True)
    price=models.DecimalField(max_digits=8,decimal_places=2,null=True)
    pub_date=models.DateField()
    publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)
    authors=models.ManyToManyField(to="Author")

    comment_count=models.IntegerField(default=0)
    up_count=models.IntegerField(default=0)
    read_count = models.IntegerField(default=0)
View Code

使用2個命令生成表

python manage.py makemigrations
python manage.py migrate

 

使用sql語句更新數據,注意:修改應用名

UPDATE app01_book SET comment_count=123, read_count=1231, up_count=2 WHERE id=1;
UPDATE app01_book SET comment_count=231, read_count=132, up_count=33 WHERE id=2;
UPDATE app01_book SET comment_count=332,read_count=132,
up_count=12 WHERE id=3;
View Code

舉例1:查詢評論數大於收藏數的書籍

常規寫法是不能執行的

ret = Book.objects.filter(comment_count__gt=read_count)

正確寫法

使用F查詢,須要導入模塊

from django.db.models import F

而後使用F查詢

def query(request):
    ret = Book.objects.filter(comment_count__gt=F("read_count")).values("title")
    print(ret)

    return HttpResponse('查詢成功')
View Code

 

Django 支持 F() 對象之間以及 F() 對象和常數之間的加減乘除和取模的操做。

舉例2:查詢評論數大於收藏數2倍的書籍

def query(request):
    ret = Book.objects.filter(comment_count__gt=F('up_count')*2).values("title")
    print(ret)

    return HttpResponse('查詢成功')
View Code

解釋:

comment_count 表示評論字段

__gt 表示大於

__lt 表示小於

 

修改操做也可使用F函數

舉例:將每一本書的價格提升30元

def query(request):
    Book.objects.all().update(price=F("price")+30)  # 更新
    ret = Book.objects.all().values("title","price") #查詢
    print(ret)

    return HttpResponse('查詢成功')
View Code

5、Q查詢

Q() 對對象的複雜查詢

Q對象(django.db.models.Q)能夠對關鍵字參數進行封裝,從而更好地應用多個查詢。能夠組合使用 &(and),(or),~(not)操做符,當一個操做符是用於兩個Q的對象,它產生一個新的Q對象。

 

filter() 等方法中的關鍵字參數查詢都是一塊兒進行「AND」 的。 若是你須要執行更復雜的查詢(例如OR 語句),你可使用Q 對象。

使用Q查詢,須要導入模塊

from django.db.models import Q

 

舉例:分別查詢做者xiao、zhang出版過的書籍名稱

Q 對象可使用& 和| 操做符組合起來。當一個操做符在兩個Q 對象上使用時,它產生一個新的Q 對象。

def query(request):
    ret = Book.objects.filter(Q(authors__name="xiao")|Q(authors__name="zhang")).values("title")
    print(ret)

    return HttpResponse('查詢成功')
View Code

等同於下面的SQL WHERE 子句:

WHERE name ="xiao" OR name ="zhang"

 

你能夠組合& 和|  操做符以及使用括號進行分組來編寫任意複雜的Q 對象。同時,Q 對象可使用~ 操做符取反,這容許組合正常的查詢和取反(NOT) 查詢:

舉例:查詢做者xiao不在2017出版過的全部書籍

def query(request):
    ret = Book.objects.filter(Q(authors__name="xiao") & ~Q(pub_date__year=2017)).values("title")
    print(ret)

    return HttpResponse('查詢成功')
View Code

等同於下面的where語句

WHERE ("app01_author"."name" = 'xiao' AND NOT ("app01_book"."pub_date" BETWEEN '2017-01-01' AND '2017-12-31'))

查詢函數能夠混合使用Q 對象和關鍵字參數。全部提供給查詢函數的參數(關鍵字參數或Q 對象)都將"AND」在一塊兒。可是,若是出現Q 對象,它必須位於全部關鍵字參數的前面。

舉例:查詢書籍名稱中包含 "python",且python不區分大小寫。在2012年或者2017年是否出版過

def query(request):
    ret = Book.objects.filter(Q(pub_date__year=2012) | Q(pub_date__year=2017),title__icontains="python").values("title")
    print(ret)

    return HttpResponse('查詢成功')
View Code
相關文章
相關標籤/搜索