1. 程式人生 > >day055&056Django之多表操作,多表查詢

day055&056Django之多表操作,多表查詢

本節內容:

1、回顧一對一、一對多、多對多的表結構關係
2、建立模型
3、新增表記錄
4、基於物件的跨表查詢
5、基於雙下劃線的跨表查詢
6、聚合查詢與分組查詢
7、F查詢與Q查詢

一、回顧一對一、一對多、多對多的表結構關係

1、一對多關係表

一本書只有一個出版社,一個出版社可以出版多本書
關聯欄位在“多”的表中
book
id  title  publish_id
1   java       1
2   go         1


publish
id name  email addr
1 AAA 123 bejing 
SQL Copy

2、多對多建立關係表

表之間的關係,書和作者的關係,一本書可以有多個作者,一個作者可以有多本書
多對多建立關係表
     Book表
     id  title  publish_id
      1   java       1
      2   go         1

      Author表
      id name
      1 alex 2 yuan book2author對應關係表(藉助第三張表) id book_id author_id 1 1 1 2 1 2 3 2 2 
SQL Copy

3、一對一關係表

關聯欄位可以建立在任意表下,但必須唯一約束。
Author
    id name  ad_id(unique約束)
    1  alex    1 2 yuan 2 AuthorDetail id gender addr gf ID author_id 1 male beijing 鐵錘 131 1 2 male beijing 鋼彈 151 2 
SQL Copy

二、建立模型

1、 例項:圖書管理

我們來假定下面這些概念,欄位和關係

作者模型:一個作者有姓名和年齡。

作者詳細模型:
把作者的詳情放到詳情表,包含生日,手機號,家庭住址等資訊。
作者詳情模型和作者模型之間是一對一的關係(one-to-one)

出版商模型: 出版商有名稱,所在城市以及email。

書籍模型:  書籍有書名和出版日期,
一本書可能會有多個作者,一個作者也可以寫多本書,所以作者和書籍的關係就是多對多的關聯關係(many-to-many);
一本書只應該由一個出版商出版,所以出版商和書籍是一對多關聯關係(one-to-many) 
Bash Copy book這個app下的models.py檔案程式碼
from django.db import models

# Create your models here.

class Book(models.Model): title = models.CharField( max_length=32) pub_date=models.DateField() price=models.DecimalField(max_digits=5,decimal_places=2) # 與Publish建立一對多的關係,外來鍵欄位建立在多的一方 publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE,null=True) # 欄位名預設為,publish_id ,on_delete級聯刪除,刪一個其他的跟著刪除 # 與Author表建立多對多的關係,ManyToManyField可以建在兩個模型中的任意一個,自動建立第三張表 authors=models.ManyToManyField("Author",db_table="book2authors") # 建立關係表, db_table關係表的名字可以在這裡設定 def __str__(self): return self.title class Publish(models.Model): name=models.CharField( max_length=32) city=models.CharField( max_length=32) email=models.CharField(max_length=32) def __str__(self): return self.name class Author(models.Model): name=models.CharField( max_length=32) age=models.IntegerField() #books=models.ManyToManyField("Book") ad=models.OneToOneField("AuthorDetail",null=True,on_delete=models.CASCADE) def __str__(self): return self.name class AuthorDetail(models.Model): birthday=models.DateField() telephone=models.BigIntegerField() addr=models.CharField( max_length=64) # author=models.OneToOneField("Author",on_delete=models.CASCADE) def __str__(self): return str(self.telephone) 
Python Copy

2、寫這個表格物件的python程式碼的—注意事項

1、表的名稱myapp_modelName,是根據 模型中的元資料自動生成的,
也可以覆寫為別的名稱,就是重新命名

2、id欄位預設會自動新增且為主鍵,可以不寫,

3、對於外來鍵欄位,Django 會在欄位名上新增"_id" 來建立資料庫中的列名
  所以我們在寫外來鍵欄位時,就只寫關聯的表名

4、這個例子中的CREATE TABLE SQL 語句使用PostgreSQL 語法格式,
  要注意的是Django 會根據settings 中指定的資料庫型別來使用相應的SQL 語句。

5、定義好模型之後,你需要告訴Django _使用_這些模型。
你要做的就是修改配置檔案中的INSTALL_APPSZ中設定,在其中新增models.py所在應用的名稱

6、外來鍵欄位 ForeignKey 有一個 null=True 的設定(它允許外來鍵接受空值 NULL),你可以賦給它空值 None 。
Bash Copy

二、新增表記錄

新增記錄前的準備工作,建立好資料庫,
1、選擇MySQL資料庫(常用),還是sqlite3資料庫,看需求。
DATABASES = {
    'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME':'day056orm', # 要連線的資料庫,連線前需要建立好 'USER':'root', # 連線資料庫的使用者名稱 'PASSWORD':'123', # 連線資料庫的密碼 'HOST':'127.0.0.1', # 連線主機,預設本級 'PORT':3306 # 埠 預設3306 }, } 注意:使用MySQL資料庫時記得在啟動資料夾下的__init__檔案中, 新增import pymysql pymysql.install_as_MySQLdb() 然後啟動python manage.py makemigrations命令和python manage.py migrate 就建立好了,我們寫好的表結構。 
Bash Copy

1、建立一些基礎表(被關聯的表)

建立publish表

建立author表

建立authordetail表:

2、繫結關係

首先在urls.py中繫結好urls分發,path('add/',views.add),
在book的app下建立好,def add(request):檢視函式

1、繫結一對多的關係

建立表記錄及繫結其對應的關係
def add(request): # 繫結一對多關係 # 建立書籍和出版社 # 方式1: # book=models.Book.objects.create(title="linux",price=122,pub_date="2012-12-12",publish_id=1) # 方式2: # pub_obj=models.Publish.objects.filter(name="人民出版社").first() # 拿到publish物件 # book=models.Book.objects.create(title="python",price=223,pub_date="2012-11-11",publish=pub_obj) # print(book.publish_id) # print(book.publish) # book書籍的出版社物件 # 查詢python書籍的出版社的郵箱 # 方式1,雙下劃線查詢 # email=models.Book.objects.filter(title="python").values("publish__email") # print(email) # email=models.Publish.objects.filter(id=book.publish_id).first().email # book是上面的表記錄物件 # print(email) # print(book.publish.email) return HttpResponse("建立成功") 核心: book.publish和book.publish_id具體是什麼? 1、book.publish # 直接拿到的是出版社物件, 2、book.publish_id # 拿到是出版社物件對應的id 
Python Copy

2、繫結多對多關係

繫結多對多的關係, 無非就是在關係表中建立記錄
繫結多對多關係
# linux這本書繫結兩個作者: alex,egon

# linux=models.Book.objects.filter(title="linux").first()
# alex=models.Author.objects.filter(name="alex").first()
# egon=models.Author.objects.filter(name="egon").first()
# linux.authors.add(alex,egon) # Book物件直接點外來鍵欄位,就可以找到第三張關係表 # # linux.authors.add(1) # 為這個Book物件新增一個作者, # linux.authors.add(*[1,2]) # 打散列表,為該書籍新增列內的所有作者 # # linux.authors.remove(alex,) # 為該書籍刪除一個作者 # linux.authors.clear() # 清空該Book物件的關係表的關聯關係 # # linux.authors.set([1,]) # set先清空之前所有的記錄(作者),重新寫入,類似於檔案寫入前清空 # 繫結多對多關係,重點是在關係表上建立記錄,做好兩個表之間的對應關係 ######### 正向操作按欄位,反向操作按表名小寫 linux = models.Book.objects.filter(title='linux').first() go = models.Book.objects.filter(title="go").first() alex = models.Author.objects.filter(name="alex").first() # 給alex作者繫結兩本書籍: linux,go alex.book_set.add(linux,go) # 單個的時候直接操作,多個物件是使用_set操作 核心:book_obj.authors.all()是什麼? 待續 
Python Copy

四、基於物件的跨表查詢

一 基於物件的跨表查詢( 子查詢:以上一次的查詢結果作為下一次的查詢條件)
   (1)一對多
                     正向查詢:按欄位 book.publish
     Book物件(多)---------------------------------- > Publish 物件 <--------------------------------- 反向查詢:按表名小寫_set.all() (2)多對多 正向查詢:按欄位 book.authors.all() Book物件 ---------------------------------- > Author 物件 <--------------------------------- 反向查詢:按表名小寫_set.all() (2)一對一 正向查詢:按欄位 book.ad Author 物件 ---------------------------------- > AuthorDetail 物件 <--------------------------------- 反向查詢:按表名小寫 
Bash Copy 基於物件的跨表查詢
def query(request): #(1)一對多 # 1 查詢linux這本書的出版社的城市(正向查詢) # book=models.Book.objects.filter(title='linux').first() # print(book.publish.city) # Book物件直接點外來鍵欄位就是出版社物件,直接點城市就行了 # 2 查詢人民出版社出版的所有書籍(反向查詢) # publish=models.Publish.objects.filter(name='人民出版社').first() # queryset=publish.book_set.all() # 這是拿到的是一個集合 # print(queryset) # <QuerySet [<Book: linux>, <Book: python>]> # 2、多對多 # 1 查詢linux書籍的所有作者(正向查詢) # linux=models.Book.objects.filter(title="linux") # queryset=linux.authors.all() # 這樣就可以拿到所有的書籍物件集合,因為設定了__str__ # print(queryset) # 2 查詢alex作者出版過的所有書籍 # alex=models.Author.objects.filter(name='alex').first() # 記得從集合中取出第一個物件 # queryset=alex.book_set.all() # 反向查詢表名_set # print(queryset) # <QuerySet [<Book: linux>]> # 3 一對一 # 1 查詢alex的手機號 # alex=models.Author.objects.filter(name="alex").first() # print(alex.ad.telephone) # 2 查詢手機號為110的作者的名字 # tel=models.AuthorDetail.objects.filter(telephone=911).first() # print(tel.author.name) # 不是集合物件,直接表名(小寫).出來 return HttpResponse("查詢成功") 
Python Copy

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

KEY:通知ORM引擎如何跨表: 正向查詢按欄位,反向查詢按表名小寫
基於雙下劃線的跨表查詢
def query(request): # 1、查詢linux這本書的出版社地址 # 方式1 正向查詢 # queryset=models.Book.objects.filter(title="linux").values("publish__city") # print(queryset) # filter得到的queryset集合物件 # 方式2 反向查詢 # queryset=models.Publish.objects.filter(book__title="linux").values("city") # print(queryset) # 2 查詢linux書籍的所有作者 # queryset=models.Book.objects.filter(title="linux").values("authors__name") # queryset=models.Book.objects.filter(title__startswith="li").values("authors__name") # 重點 # print(queryset) # queryset=models.Author.objects.filter(book__title="linux").values("name") # 反向查詢 # 3 查詢alex的手機號 # queryset=models.Author.objects.filter(name="alex").values("ad__telephone") # 正向 # queryset=models.AuthorDetail.objects.filter(author__name="alex").values("telephone") # 反向 # print(queryset) # 連續跨表 # 4 查詢人民出版社出版過的所有書籍的名字及作者的姓名 queryset=models.Book.objects.filter(publish__name="人民出版社").values("title","authors__name") # 正向查詢 # queryset=models.Author.objects.filter(book__publish__name="人民出版社").values("book__title","name") # 反向查詢 # 預設都是left join,所以如果有存在的左邊基準的值為空,那麼就會不保留這條記錄 print(queryset) return HttpResponse("查詢成功")