1. 程式人生 > >Django - ORM 多對多關係 - 中間關係表的建立方式探討

Django - ORM 多對多關係 - 中間關係表的建立方式探討

目錄

多對多關係 - 三種中間表的建立方式 - 優劣總結

方式一、手動建立第三張表

方式二、自動建立第三張表 - MandyToManyField

方式三、半自動建立第三張表 -- 手動建立第三張表+ManyToMany建立關係(推薦使用)


多對多關係 - 三種中間表的建立方式 - 優劣總結

  • 手動建立第三張表(A表,B表,A2B表),A、B內不建立與A2B的關聯關係 -- 增刪改查操作繁雜 不建議使用

  • 自動建立第三張表 -- 刪改查很方便,但是欄位固定,對中間關係表新增欄位難以實現

  • 半自動建立第三張表(手動穿件第三張表(中間關係表),自動建立三表的關係) -- 建議使用

    • through('A2B表名') :指定手動建立的關係表(A2B)

    • through_fields('A2B表內當前表關係欄位','A2B表內關係表的欄位'):中介模型

方式一、手動建立第三張表

注意:

  • A,B 表內未建立與A2B表的關聯
  • 查詢必須通過第三張表進行 ,無法使用基於下劃線的跨表查詢
  • 新增操作必須操作三張表,A表新增物件,B表獲取物件,A2B表儲存二者物件
# models內三個表的建立

from django.db import models


# Create your models here.

class Book(models.Model):
    # 預設會建立id
    name = models.CharField(max_length=32)


class Author(models.Model):
    name = models.CharField(max_length=32)


class Book2Author(models.Model):
    id = models.AutoField(primary_key=True)
    # 手動通過外來鍵關聯欄位
    book=models.ForeignKey(to='Book',to_field='id')
    author=models.ForeignKey(to='Author',to_field='id')
from app01 import models

# 查詢紅樓夢這本書所有的作者 全手動

book=models.Book.objects.filter(name='紅樓夢').first()
authors=models.Book2Author.objects.filter(book=book).values_list('author_id')
print(authors)
ll=[i[0] for i in authors]
# ll=[1,2]
author_list=models.Author.objects.filter(id__in=ll)
print(author_list)

#   給紅樓夢這本書新增n這個作者
author=models.Author.objects.filter(name='n').first()
book = models.Book.objects.filter(name='紅樓夢').first()

#去中間表存
ret=models.Book2Author.objects.create(book=book,author=author)
# 給紅樓夢這本書,刪除lqz這個作者

方式二、自動建立第三張表 - MandyToManyField

注意:

  • related_name 關聯物件反向引用描述符 - 通過book可以引用到Book表中物件
  • 只需要操作兩個表在models內
  • 以為未在models內操作第三張表,所以後期對第三張表的操作無法新增欄位(可以通過伺服器,但是不推薦)
from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="書名")
    # verbose_name admin中顯示的表名稱


class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者姓名")
    # 通過ORM自帶的ManyToManyField自動建立第三張表
    books = models.ManyToManyField(to="Book", related_name="authors")
    # related_name 關聯物件反向引用描述符 - 通過book可以引用到Book表中物件
    # Book.object.filter(name = '紅樓夢').authors.all() - 獲取book表內紅樓夢的所有作者
    # 可解決外來鍵重名問題
from app03 import models as m3

# 第三種方式,全自動建立

# 查詢紅樓夢這本書的所有作者
book = m3.Book.objects.filter(title='紅樓夢').first()
print(book)
# 通過 related_name="authors"
print(book.authors.all())
# 通過反向查詢 被relate_name代替無法操作
# print(book.author_set.all())

# 正向查詢 查詢作者名叫n1的所有書籍
a = m3.Author.objects.filter(name='n1').first()
print(a)
print(a.books.all())

#   給紅樓夢這本書新增n這個作者
author = m3.Author.objects.filter(name='n1').first()
print(author)
book = m3.Book.objects.filter(title='紅樓夢').first()
# 使用add新增
author.books.add(book)

方式三、半自動建立第三張表 -- 手動建立第三張表+ManyToMany建立關係(推薦使用)

注意:

  • through('A2B表名') :指定手動建立的中間關係表(A2B)

  • through_fields('A2B表內當前表關係欄位','A2B表內關係表的欄位'):中介模型

  • 三張表都建立了內部聯絡,可以使用雙下劃綫和基於物件的正方形查詢方式

from django.db import models
# Create your models here.

# 手動建立第三張表,查詢還方便的查詢
class Book(models.Model):
    # 預設會建立id
    name = models.CharField(max_length=32)
    # 中介模型,手動指定第三張中間表是Book2Author
    authors = models.ManyToManyField(to='Author', through='Book2Author', through_fields=('book', 'author'))


class Author(models.Model):
    name = models.CharField(max_length=32)

    def __str__(self):
        return self.name


class Book2Author(models.Model):
    id = models.AutoField(primary_key=True)
    book = models.ForeignKey(to='Book', to_field='id')
    author = models.ForeignKey(to='Author', to_field='id')

 

from app02 import models as mo2

#     第二種方式 半自動

# 基於物件的查詢(存在正向反向)
# 查詢紅樓夢這本書所有的作者 -正向
book = mo2.Book.objects.filter(name='西遊記').first()
print(book.authors.all())

# n1作者查書名 - 反向
a = mo2.Author.objects.filter(name='n1').first()
print(a.book_set.all())


# 基於雙下劃線的查詢(可以簡單忽視正反)
# 查詢紅樓夢這本書所有的作者的名字
ret=mo2.Author.objects.filter(book__name='西遊記').values('name')
print(ret)


# 刪除,給西遊記這本書,刪除n2這個作者
ret=mo2.Book2Author.objects.filter(book__name='西遊記',author__name='n2').delete()
print(ret)