1. 程式人生 > 實用技巧 >django框架之ORM多表查詢等相關內容-68

django框架之ORM多表查詢等相關內容-68

1 多表操作之模型建立

1 圖書表:book,作者表:author,作者詳情表:authordetail,出版社表:publish,(第三張中間表)
2 作者跟作者詳情:是一對一,關聯欄位寫在哪一方都可以
3 圖書跟出版社:是一對多,一對多關係一旦確立,關聯欄位寫在多的一方
4 圖書和作者:是多對多,多對多的關係需要建立第三張表(可以自動生成)

5 models.py中把關係建立出來
from django.db import models
### django: 1.11.1 2.0.7
# Create your models here.
class Publish(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
addr = models.CharField(max_length=64)
phone = models.CharField(max_length=64)
email = models.EmailField()


class Book(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=6, decimal_places=2)
publish_date = models.DateTimeField(auto_now_add=True)

# to='Publish'跟Publish表做關聯(ForeignKey,一對多)
# to_field='id'跟哪個欄位做關聯
# publish=models.CharField(max_length=32)
# publish=models.ForeignKey(to='Publish',to_field='id')
# publish = models.ForeignKey(to='Publish') # 不寫,預設跟主鍵做關聯
publish = models.ForeignKey(to=Publish) # 不寫,預設跟主鍵做關聯

# 自動創建出第三張表(這句話會自動建立第三章表)
# authors在資料庫中不存在該欄位,沒有to_field
# 預設情況:第三張表有id欄位,當前Book表的id和Author表的id欄位
authors=models.ManyToManyField(to='Author')


class Author(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
age = models.SmallIntegerField()
# 一對一的本質是 ForeignKey+unique
author_detail=models.OneToOneField(to='AuthorDetail',to_field='id')
# author_detail=models.ForeignKey(to='AuthorDetail',to_field='id',unique=True)


class AuthorDetail(models.Model):
id = models.AutoField(primary_key=True)
sex = models.SmallIntegerField()
addr = models.CharField(max_length=64)
phone = models.BigIntegerField()


6 同步到mysql資料庫
-配置檔案
-pymysql.install_as_mysqldb()
-公司可以用過的mysqlclient
-兩條命令

7 2.x版本的django
-外來鍵欄位必須加 引數:on_delete
-1.x版本不需要,預設就是級聯刪除
-假設,
刪除出版社,該出版社出版的所有圖書也都刪除,on_delete=models.CASCADE
刪除出版社,該出版社出版的圖書不刪除,設定為空on_delete=models.SET_NULL,null=True
刪除出版社,該出版社出版的圖書不刪除,設定為預設on_delete=models.SET_DEFAULT,default=0

2 一對多新增記錄

publish=models.Publish.objects.create(name='北京出版社',addr='北京',phone='0536-12345678',email='郵箱地址')
# 新增青樓夢圖書
book=models.Book.objects.create(name='青樓夢',price='23.45',publish=publish)# publish=物件
# book=models.Book.objects.create(name='西遊記',price='23.55',publish_id=1)# publish_id=數字
# 新增西遊記
book=models.Book.objects.create(name='西遊記',price='23.55',publish_id=publish.id)# publish_id=數字


# 總結:
1 email可以不傳email,本質就是varchar(admin中會判斷)
2 新增圖書:
-publish=publish
-publish_id=publish.id
3 寫在表模型中的publish欄位,到資料庫中會變成publish_id(ForeignKey)
4 查到book物件以後
-book.publish 物件
-book.publish_id id號,數字

3 多對多新增記錄,修改,刪除

1 自動建立的表,表模型就拿不到,book.authors代指表模型


# 多對多,作者和書
# 給西遊記這本書新增兩個作者lqz和egon
# 去到西遊記這本書
# book=models.Book.objects.get(name='西遊記')
# 代指中間表book.authors
# lqz=models.Author.objects.get(id=2)
# egon=models.Author.objects.get(id=3)
# book.authors.add(2,3) # 新增作者,通過id新增
# # book.authors.add(lqz,egon) # 新增作者,通過物件新增
# book.authors.add(2,egon) # 新增作者,通過物件新增

# 西遊記刪除一個作者
# book = models.Book.objects.get(name='西遊記')
# book.authors.remove(2)
# egon = models.Author.objects.get(id=3)
# book.authors.remove(egon)

# clear 清空所有作者
book = models.Book.objects.get(name='西遊記')
# book.authors.add(2, 3)
# book.authors.clear()

# set 先清空,再add,前提是不存在的作者
book.authors.set([4, ])

# add ,remove,set clear

4 多對對多其他api

# add ,remove,set clear

5 基於物件的跨表查詢(正向反向)

# 跨表查詢有兩種方式
-基於物件的跨表查詢:子查詢
-基於雙下劃線的跨表查詢:關聯查詢,連表查詢


# 基於物件的跨表查詢
-查詢主鍵為1的書籍的出版社所在的城市

# 基於物件的跨表查詢(子查詢)
# 一對多
# 查詢主鍵為1的書籍的出版社所在的城市
# book=models.Book.objects.get(id=1) # 第一次查詢
# # book=models.Book.objects.filter(id=1).first()
# publish=book.publish # 內部又執行了一次查詢,根據publish_id查詢publish
# print(publish.addr)

# 北京出版社出版的所有書籍
# publish=models.Publish.objects.get(name='北京出版社') # 第一次查詢了出版社
# books=publish.book_set.all() # 表名小寫_set # 第二次,根據出版社id,查詢所有書
# print(books)

# 正向查詢:book表內有publish欄位 直接物件.欄位名
# 反向查詢:publish表內沒有book欄位,出版社物件.Book小寫_set.all()


### 一對一
# 查詢所有住址在山東的作者的姓名
# 反向查詢:author_detail沒有author欄位,author_detail.表明小寫
# author_detail=models.AuthorDetail.objects.filter(addr__contains='山東').first()
# # 反向
# print(author_detail.author.name)

# 查詢egon作者的地址
# 正向
# author=models.Author.objects.get(name='egon')
# print(author.author_detail.addr)


# 多對多關係查詢
#青樓夢所有作者的名字以及手機號
# book=models.Book.objects.get(name='青樓夢')
# # 正向
# authors=book.authors.all()
# for author in authors:
# print(author.name)
# print(author.author_detail.phone)

# 反向 查詢egon出過的所有書籍的名字
# egon=models.Author.objects.get(name='egon')
# books=egon.book_set.all()
# for book in books:
# print(book.name)

6 基於雙下劃線的跨表查詢

# 連表查詢
# 基於物件的跨表查詢,先查物件,通過物件再去查另一個物件(正向:欄位名,反向:表名小寫/表名小寫_set.all())


# 地址為山東的作者寫的所有書
# author_detail=models.AuthorDetail.objects.get(addr='山東')
# author=author_detail.author
# books=author.book_set.all()
# print(books[0].name)

# (作業)地址為山東的作者寫的所有書的出版社名字


### 基於雙下劃線的跨表查之 一對多
# 正向:欄位名
# 反向:表名小寫
# filter,values,values_list(寫 __ 跨表)
# 練習: 查詢北京出版社出版過的所有書籍的名字與價格(一對多)
# SELECT `app01_book`.`name`, `app01_book`.`price` FROM `app01_publish` LEFT OUTER JOIN `app01_book` ON (`app01_publish`.`id` = `app01_book`.`publish_id`) WHERE `app01_publish`.`name` = '北京出版社' ;
# res=models.Publish.objects.filter(name='北京出版社').values('book__name','book__price')
# print(res)
#SELECT `app01_book`.`name`, `app01_book`.`price` FROM `app01_book` INNER JOIN `app01_publish` ON (`app01_book`.`publish_id` = `app01_publish`.`id`) WHERE `app01_publish`.`name` = '北京出版社';

# res=models.Book.objects.filter(publish__name='北京出版社').values('name','price')
# print(res)


## 多對多
# 練習: 查詢egon出過的所有書籍的名字,價格(多對多)
#反向
# res=models.Author.objects.filter(name='egon').values('book__name','book__price')
# print(res)

# 正向
# res=models.Book.objects.filter(authors__name='egon').values('name','price')
# print(res)

#查詢egon的手機號
# res=models.Author.objects.filter(name='egon').values('author_detail__phone')
# print(res)
# res=models.AuthorDetail.objects.filter(author__name='egon').values('phone')
# print(res)

7 進階連續跨表查詢

  # 連續跨表
#查詢北京出版社出版過的所有書籍的名字以及作者的姓名
# res=models.Publish.objects.filter(name='北京出版社').values('book__name','book__authors__name')
# print(res)

# res=models.Book.objects.filter(publish__name='北京出版社').values('name','authors__name')
# print(res)

# res=models.Author.objects.filter(book__publish__name='北京出版社').values('book__name','name')
# print(res)

# 手機號以189開頭的作者出版過的所有 書籍名稱 以及 出版社名稱
# res=models.AuthorDetail.objects.filter(phone__startswith='189').values('author__book__name','author__book__publish__name')
# print(res)

# SELECT `app01_book`.`name`, `app01_publish`.`name` FROM `app01_author` INNER JOIN `app01_authordetail` ON (`app01_author`.`author_detail_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`.`phone` LIKE '189%' ;
res=models.Author.objects.filter(author_detail__phone__startswith='189').values('book__name','book__publish__name')
print(res)

擴充套件

1 看一看這篇部落格

https://www.cnblogs.com/nokiaguy/p/13803370.html

2 安裝模組相關

pip3 install django  
# 本質是去https://pypi.python.org/simple,搜這個模組,會根據你的平臺下載在一個安裝包(windows平臺是whl),下載完,再安裝

# pip安裝失敗的情況
# 我們可以繞過它,有了whl檔案以後,自己裝
# https://www.lfd.uci.edu/~gohlke/pythonlibs/#opencv
pip3 install django.whl

# 官方庫沒有上傳到pypi,官方也不給製作whl檔案
#如何安裝 包 (setup.py)
到達安裝目錄,setup.py所在的目錄
python setup.py build
python setup.py install

# 配置清華源,豆瓣源,本質是
豆瓣源會把pypi,包拉到自己的伺服器上,以後你再下,去它的伺服器上下,所以速度快

# 你自己寫的包,如何上傳到pypi上給別人使用?

3 外來鍵關係要不要建立

1 關聯欄位與外來鍵約束沒有必然的聯絡(建管理欄位是為了進行查詢,建約束是為了不出現髒資料)
2 預設情況,關聯關係建好以後,外來鍵約束就自然建立了
3 實際工作中,外來鍵約束一般不建(影響效率),都是人為約束(程式碼約束)
-db_constraint=False
4 表模型和資料庫表的對應,不要直接修改表(這是可以的,但是不建議),要修改表模型,同步到表中