多表操作

一、Django多表orm設計規則

1. 關聯的表之間建議建立外鍵,但可以取消關聯關係(db_constraint=False)
2. 關聯表之間的外鍵字段建議採用對應類名的全小寫
3. 採用關聯表的主鍵或對象均能進行操作

# 例表設計:
# 書籍 Book: id name price publish_date publish author(多對多關聯字段)
# 出版社 Publish: id name address
# 作者 Author: id name author_detail
# 作者詳情 AuthorDetail: id age telephone info

modles設計:

# 一對多:出版社(一) 書籍(多,外鍵在多的一方,依賴於出版社)
# 一對一:作者詳情(一) 作者(一,外鍵在任意一方均可,一旦外鍵放在作者中,作者依賴於作者詳情)
# 多對多:作者(多)書籍(多)建立關係表(存放兩個表的外鍵信息 => 將建錶轉化為關係對應字段)

# Book書籍:id  name  price  publish_date  publish(publish_id)
class Book(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=20)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish_date = models.DateField()
    publish = models.ForeignKey(to='Publish', to_field='id')
    # 多對多關係字段,該字段不會再book表中形成字段,是用來創建關係表的
    author = models.ManyToManyField(to='Author')

# Author作者:id  name
class Author(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=20)
    # author_detail = models.ForeignKey(to='AuthorDetail', to_field='id', unique=True)
    author_detail = models.OneToOneField(to='AuthorDetail', to_field='id')

# AuthorDetail作者詳情: id  age  telephone  info
class AuthorDetail(models.Model):
    id = models.AutoField(primary_key=True)
    age = models.IntegerField()
    telephone = models.IntegerField()
    # 存大文本
    info = models.TextField()

# Publish出版社:id  name  address
class Publish(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=20)
    address = models.CharField(max_length=64)

View Code

二、一對多關係

1、規則:

1. 關係中 『多』 依賴於 『一』
2. Django 1.x外鍵關聯默認有級聯刪除,2.x需要手動明確外鍵的級聯刪除(on_delete=models.CASCADE)

2、增刪改操作

# 1、增
# 先有出版社,才有書籍
publish = Publish.objects.create(name="老男孩出版社", address="上海核心基地")
# 外鍵為關聯對象
Book.objects.create(name='死亡Python', price=88.88,  publish_date='2018-8-8', publish=publish)   # 此處返回的是一個對象

id = Publish.objects.create(name="小女孩出版社", address="宇宙中心").id
# 外鍵字段為關聯對象主鍵
Book.objects.create(name='滅霸Linux', price=120.00, publish_date='2015-8-8', publish_id=id)

# 2、刪
# 刪除出版社,默認有級聯刪除,出版社出版的數據全會被刪除
Publish.objects.first().delete()

# 3、改
# 書籍的出版社修改必須為已存在的出版社
publish = Publish.objects.create(name="Owen出版社", address="御花園")
Book.objects.filter(pk=1).update(publish=publish)  # pk代表主鍵

三、一對一關係

1、規則

    通過外鍵所在表決定依賴關係,有外鍵的表依賴於外鍵所對應的另一張表。

2、增刪改操作

# 操作規則同一對多關係,有外鍵的表 依賴於 另一張表

# 增:遵循操作順序
author_detail = AuthorDetail.objects.create(age=18, telephone=13860357890, info="帥")
Author.objects.create(name='Sandy', author_detail=author_detail)

# 刪:擁有級聯刪除
AuthorDetail.objects.first().delete()

# 改:一般不考慮該關聯字段

四、多對多關係

1、規則:

  1. 多對多關係存在關係表,關係表建議採用ManyToManyField字段處理;
  2. 需要手動創建關係表時,在字段中明確through與through_field值。

2、增刪改操作:

通過關係表字段存在的類的對象獲取關係表 book.author
b1 = Book.objects.first()  # type: Book
b2 = Book.objects.all()[1]  # type: Book
a1 = Author.objects.first()  # type: Author
a2 = Author.objects.all()[1]  # type: Author

# 增:為書籍添加作者的主鍵或對象們
# book.author.add(*args)  # 此處的book為Book的對象
b1.author.add(a1.id, a2.id)
b2.author.add(a1, a2)

# 刪:刪除書籍已有作者的主鍵或對象們
#  book.author.remove(*args)   # 此處的book為Book的對象
b1.author.remove(a1)
b1.author.remove(a2.id)

# 改:清空並添加作者的主鍵或對象 | 設置作者的主鍵或對象形式的列表
# book.author.clear()      # 此處的book為Book的對象
b1.author.clear()

# book.author.add(*args)    # 此處的book為Book的對象
b1.author.add(a1)

# book.author.set([*args])    # 此處的book為Book的對象
b2.author.set([a2.id, a3.id])

五、跨表查詢規則

  1. 正向逆向概念:從存放外鍵的表到關係表稱之為正向跨表查詢,反之稱之為逆向查詢;
  2. 正向查詢通過外鍵屬性名進行跨表查詢;
  3. 逆向查詢通過關聯表對應類名小寫進行跨表查詢,逆向查詢遇到多條結果,在類名後再添加_set

基於對象的跨表查詢

在跨表查詢的規則上,跨表查詢的結果為多條數據時需要在字段後添加_set

# 一對一
author = Author.objects.first()  # 查詢得到作者對象
author_detail = author.author_detail  # 基於對象跨表獲取作者詳情對象,正向通過字段名 author_detail
author = author_detail.author  # 基於對象跨表獲取作者對象,逆向通過表名小寫 author

# 一對多
book = Book.objects.first()  # 查詢得到書籍對象
publish = book.publish  # 獲取出版社對象,正向通過字段名 publish
book_list = publish.book_set.all()  # 獲取書籍對象們,逆向通過表名小寫 book,多條數據添加_set

# 多對多
book = Book.objects.first()  # 查詢得到書籍對象
author_list = book.author   # 獲取作者對象們,正向通過字段名 author

author = Author.objects.first()
book_list = author.book_set  # 獲取書籍對象們,逆向通過表名小寫 book,多條數據添加_set

# 多級跨表
# 案例一:某作者出版的第一本書的出版社名字
author.book_set.first().publish.name

 七、基於下劃線的跨表查詢

滿足跨表查詢規則
filter方法與values方法支持__查詢規則

# 案例

# 兩表關聯:查詢所有小於18歲作者的名字與實際年齡
authors_dic = Author.objects.filter(author_detail__id__gt=0).values('name', 'author_detail__age')

# 多表關聯:查詢出版社在上海的出版過的所有書的 作者姓名、作者電話、具體出版社名 的相關信息
info_dic = Book.objects.filter(publish__address__contains="上海").values('author__name', 'author__author_detail__telephone', 'publish__name')