1、建立表結構
三個表:book、Author、publisher。
書籍和作者是多對多的關系,一本書可以有多個作者,一個作者可以有多本書。
出版社和書籍是一對多的關系,一個出版社可以出版多本書(多方,多方定義外鍵),一本書只能由某一個出版社出版(現實情況可能不同,只是我們這里這樣規定。)
from django.db import models# Create your models here.
class Book(models.Model):title = models.CharField(max_length=100, verbose_name='書名')authors = models.ManyToManyField('Author', verbose_name='作者')publisher = models.ForeignKey('Publisher', on_delete=models.CASCADE, verbose_name='出版社')class Meta:verbose_name = '圖書'verbose_name_plural = '圖書'def __str__(self):return self.titleclass Author(models.Model):name = models.CharField(max_length=50, verbose_name='作者名')date_of_birth = models.DateField(verbose_name='出生日期', blank=True, null=True)class Meta:verbose_name = '作者'verbose_name_plural = '作者'def __str__(self):return self.nameclass Publisher(models.Model):name = models.CharField(max_length=100, verbose_name='出版社名')address = models.CharField(max_length=255, verbose_name='地址', blank=True, null=True)website = models.URLField(verbose_name='網站', blank=True, null=True)class Meta:verbose_name = '出版社'verbose_name_plural = '出版社'def __str__(self):return self.name
2、一對多(ForeignKey)
數據添加
一對多添加數據需要先添加“一”端,否則多端沒有外鍵引用無法添加,所以需要先有出版社信息
我們這里手工添加一個:
Publisher.objects.create(name="中信出版社", address="河北省廊坊市", website="www.publisher.com")
添加書籍信息,所屬”中信出版社“
# 先查詢取得出版社的對象
publisher = Publisher.objects.get(id=1)
book = Book.objects.create(title="射雕英雄傳", publisher=publisher)
數據查詢
查詢數據有兩個方向,根據多方查詢一方稱為“正向”,根據一方取得多方數據稱為“反向”
正向:有了書籍(多方)數據,查詢出版社數據(一方)
方式:直接用“.”關聯數據
book = Book.objects.filter(title="射雕英雄傳").first()
print(book) # 射雕英雄傳
print(book.publisher) # 中信出版社
print(book.publisher.address) # 河北省廊坊市
反向:有了出版社,查詢書籍
方式:小寫類名_set.all(),book_set.all()
publisher = Publisher.objects.filter(name="中信出版社").first()
# 方式一:用兩步,通過一個變量引用所有書籍
books = publisher.book_set.all()
for book in books:print(book)# 方式二,不要中間變量,直接輸出
print(publisher.book_set.all()[0]) # 輸出 queryset的第一個對象
3、多對多
在后臺,多對多關系在Django里,實際上是將兩個多方的表名作為字段名,新增了一個表,來維護多對多關系。
數據添加
多對多的情況下,雖然兩個都是“多方”,是對稱的。但是在models中構建的時候,是把一個對象名稱+s,作為另一個對象的ManyToManyField字段
class Book(models.Model):authors = models.ManyToManyField('Author', verbose_name='作者')
這樣在編程的時候就不是對稱的,所以添加的時候兩方添加方式是有區別的。
book.authors.add(author1, author2) # book 里面有authors字段,所以這樣添加
author.book_set.add(book1, book2) # author里面沒有books字段
正向,從定義對方字段的那一方開始
# 方式一,傳單獨的對象
rong = Author.objects.filter(name="黃蓉").first() # 這里必須用.first(),否則返回的是queryset,而不是對象
jing = Author.objects.filter(name="郭靖").first()
bird = Book.objects.filter(title="射雕英雄傳").first()
bird.authors.add(rong, jing) # 將rong、jing兩個Author對象關聯到book# 方式二,傳queryset
from django.db.models import Q
authors = Author.objects.filter(Q(name="黃蓉") | Q(name="郭靖"))
bird = Book.objects.filter(title="射雕英雄傳").first()
bird.authors.add(*authors) # 注意前面要用*
# 或者傳id列表,假設1、3為兩個作者的id
bird.authors.add(*[1, 3]) # 注意前面要用*
刪除所有關聯關系,不會刪除對象
bird.authors.clear()
反向,沒有定義另一方字段的一方
bird = Book.objects.get(title="射雕英雄傳")
rong = Author.objects.filter(name="黃蓉").first()
rong.book_set.add(bird) # 也可以添加多本書,如果有的話
創建新對象,并加入關聯對象集
publisher = Publisher.objects.filter(name="中信出版社").first()
author = Author.objects.filter(name="黃蓉").first()
book = author.book_set.create(title="神雕俠侶", publisher=publisher) # 這里創建的是book類,也可以返回創建的對象
刪除對象關聯
author.book_set.remove(bird) # 刪除其中一個對象的關聯
author.book_set.clear() # 刪除所有關聯關系,不會刪除對象
數據查詢
多對多的數據查詢根據“誰定義了以對方表名為名字的字段”也有正向、反向。方法同一對多。