django orm级联_Django数据表关联关系映射(一对一、一对多、多对多)
我們知道涉及到數據表之間的對應關系就會想到一對一、一對多、多對多,在學習 MySQL 數據庫時表關系設計是需要重點掌握的知識。Django 中定義了三種關系類型的字段用來描述數據庫表的關聯關系:一對多(Foreignkey)、一對一(OneToOneFiled)、以及多對多(ManyToManyFiled),在本節我們對它們做簡單的介紹。
1. 一對多關系類型
這種類型在數據庫中體現是外鍵關聯關系,它在和其他的 Model 建立關聯同時也和自己建立關聯,用來描述一對多的關系,例如一個作者可以寫很多不同的書,但是這些書又只能對應這一個作者,再比如一本圖書只能屬于一個出版社,一個出版社可以出版很多不同種類的圖書,這就是一對多的關系。Django 會自動將字段的名稱添加“_id”作為列名,ForgienKey 的定義如下:
class django.db,model.ForeignKey(to,on_delete,**options)
1) 必填參數
它有兩個必填參數。to,指定所關聯的 Model,它的中取值可以是直接引用其他的 Model,也可以是 Model 所對應的字符串名稱;on_delete,當刪除關聯表的數據時,Django 將根據這個參數設定的值確定應該執行什么樣的 SQL 約束。
on_delete 可以理解為 MySQL 外鍵的級聯動作,當主表執行刪除操作時對子表的影響,即子表要執行的操作,Django 提供的可選值如下所示:
CASCADE,級聯刪除,它是大部分 ForeignKey 的定義時選擇的約束。它的表現是刪除了“主”,則“子”也會被自動刪除。
PROTECT,刪除被引用對象時,將會拋出 ProtectedError 異常。當主表被一個或多個子表關聯時,主表被刪除則會拋出異常。
SET_NULL,設置刪除對象所關聯的外鍵字段為 null,但前提是設置了選項 null 為True,否則會拋出異常。
SET_DEFAULT:將外鍵字段設置為默認值,但前提是設置了 default 選項,且指向的對象是存在的。
SET(value):刪除被引用對象時,設置外鍵字段為 value。value 如果是一個可調用對象,那么就會被設置為調用后的結果。
DO_NOTHING:不做任何處理。但是,由于數據表之間存在引用關系,刪除關聯數據,會造成數據庫拋出異常。
2) 可選參數
除了必填參數以外,ForeignKey 還有一些常用的可選參數需要關注。如下所示:
to_field:關聯對象的字段名稱。默認情況下,Django 使用關聯對象的主鍵(大部分情況下是 id),如果需要修改成其他字段,可以設置這個參數。但是,需要注意,能夠關聯的字段必須有 unique=True 的約束。
db_constraint:默認值是 True,它會在數據庫中創建外鍵約束,維護數據完整性。通常情況下,這符合大部分場景的需求。如果數據庫中存在一些歷史遺留的無效數據,則可以將其設置為 False,這時就需要自己去維護關聯關系的正確性了。
related_name:這個字段設置的值用于反向查詢,默認不需要設置,Django 會設置其為“小寫模型名 _set”。
related_query_name:這個名稱用于反向過濾。如果設置了 related_name,那么將用它作為默認值,否則 Django 會把模型的名稱作為默認值。
3) 語法格式
#一個A類實例對象關聯多個B類實例對象
class A(model.Model):
....
class B(model.Model):
屬性 = models.ForeignKey(多對一中"一"的模型類, ...)
4) 實例應用
修改原來在《Django ORM進階之項目實戰》定義的代碼,將出版社與圖書之間修改為一對多的關系,添加如下代碼:
from django.db import models
#新建出版社表
class PubName(models.Model):
pubname=models.CharField('名稱',max_length=255,unique=True)
#更改書籍信息表
class Book(models.Model):
title=models.CharField(max_length=30,unique=True, verbose_name='書名')
price=models.DecimalField(max_digits=7,decimal_places=2,verbose_name='定價')
#添加默認價格
def default_price(self):
return '¥30'
#零售價格
retail_price=models.DecimalField(max_digits=7,decimal_places=2,verbose_name='零售價',default=default_price)
pub=models.ForeignKey(to=PubName,on_delete=models.CASCADE ,null=True) #創建Foreign外鍵關聯pub,以pub_id關聯
def __str__(self)
return "title:%s pub:%s price:%s" % (self.title, self.pub, self.price)
此處需要注意每次更改完 models 都需要進行數據庫遷移操作,依次執行以下命令即可:
python manager.py makemigrations
python manager.py migrate
插入數據創建一對多對象,如下所示:
#創建PubName實例化對象pub1并插入書籍信息
pub1=PubName.objects.create(pubname="清華出版社")
Book.objects.create(title="Python",price="59.00",retail_price="59.00",pub=pub1)
Book.objects.create(title="Redis",price="25.00",retail_price="25.00",pub=pub1)
Book.objects.create(title="Java",price="45.00",retail_price="45.00",pub=pub1)
#創建PubName實例化對象pub2并插入書籍信息
pub2=PubName.objects.create(pubname="c語言中文網出版")
Book.objects.create(title="Django",price="65.00",retail_price="65.00",pub=pub2)
Book.objects.create(title="Flask",price="45.00",retail_price="45.00",pub=pub2)
Book.objects.create(title="Tornado",price="35.00",retail_price="35.00",pub=pub2)
訪問 MySQL 數據庫分別查詢 index_book、index_pubname 數據表(如下所示),index_pubname 數據表的 id 字段作為唯一值關聯多個書籍信息,ForeignKey 外鍵關聯鍵自動在 index_book 表中生成 pub_Id 字段并作為關聯字段。此時 index_pubname 作為主表而 index_book 是子表,主表的 id 是子表的外鍵,兩者之間存在外鍵約束 CASCADE。
mysql> select * from index_book;
+----+---------+--------+-------+--------------+
| id | title | pub_id | price | retail_price |
+----+---------+--------+-------+--------------+
| 1 | Python | 1 | 59.00 | 59.00 |
| 2 | Redis | 1 | 25.00 | 25.00 |
| 3 | Java | 1 | 45.00 | 45.00 |
| 4 | Django | 2 | 65.00 | 65.00 |
| 5 | Flask | 2 | 45.00 | 45.00 |
| 6 | Tornado | 2 | 35.00 | 35.00 |
+----+---------+--------+-------+--------------+
6 rows in set (0.01 sec)
mysql> select * from index_pubname;
+----+-----------------+
| id | pubname |
+----+-----------------+
| 1 | c語言中文網出版 |
| 2 | 清華出版社 |
+----+-----------------+
6 rows in set (0.00 sec)
2. 一對一關系類型
OneToOneFiled 繼承自 ForeignKey,在概念上,它類似 unique=Ture 的 ForeignKey,它與 ForeignKey 最顯著的區別在于反向查詢上,ForeignKey 反向查詢返回的是一個對象實例列表,而?OneToOneFiled 反向查詢返回的是一個對象實例。
一對關系類型的使用和場景相對其他兩種關聯關系要少,經常用于對已有 Model 的擴展,例如我們可以對 UserInfo 表進行擴展,添加類似用戶昵稱、個性簽名等字段。此時就可以新建一個 Model,并定義一個字段與 UserInfo 表一對一關聯。這樣就實現了用戶信息拓展表與 UserInfo 表一對一關聯,下面會用通過實例進行說明。
1) 語法格式
class A(model.Model):
...
class B(model.Model):
屬性 = models.OneToOneField(A)
2) 實例應用
新建 index\models.py 下添加以下代碼:
#新建一對一關用戶信息表拓展表,添加完成后執行數據庫遷移同步操作
class ExtendUserinfo(models.Model):
user=models.OneToOneField(to=UserInfo,on_delete=models.CASCADE)
signature=models.CharField(max_length=255,verbose_name='用戶簽名',help_text='自建簽名')
nickname=models.CharField(max_length=255,verbose_name='昵稱',help_text='自建昵稱')
使用 Django shell 創建數據,如下所示:
from index.models import UserInfo,ExtendUserinfo
username=UserInfo.objects.create(username="xiaoming",password="******")
username=UserInfo.objects.create(username="xiaohong",password="*******",gender="F")
#創建一對一表關聯
ExtendUserinfo.objects.create(user=username,signature="good good study,day day up",nickname="XH")
3) MySQL數據表顯示
最后通過訪問 MySQL 數據庫,我們可以得到如下所示數據表,使用 user_id 進行表之間的關聯:
mysql> select * from index_userinfo;
+----+----------+----------+--------+
| id | username | password | gender |
+----+----------+----------+--------+
| 1 | xiaoming | ****** | M |
| 2 | xiaohong | ******* | F |
+----+----------+----------+--------+
2 rows in set (0.00 sec)
mysql> select * from index_extenduserinfo;
+----+----------------------------+----------+---------+
| id | signature | nickname | user_id |
+----+----------------------------+----------+---------+
| 1 | good good study,day day up | XH | 2 |
+----+----------------------------+----------+---------+
1 row in set (0.00 sec)
3. 多對多關系類型
多對多關系也是比較常見的,比如一個作者可以寫很多本書,一本書也可以由很多作者一起完成,那么這時候 Author 和 Book 之間就是多對多的關系。 Django 通過中間表的方式來實現 Model 之間的多對多的關系,這和 MySQL 中實現方式是一致的。這個中間表我們可以自己提供,也可以使用 Django 默認生成的中間表。
1) ManyToManyFiled定義
class django.db.models.ManyToManyFiled(to,**options)
它只有一個必填的參數即 to,與其他兩個關聯詞在一樣,用來指定與當前的 Model 關聯的 Model。
2)可選參數
當然?ManyToManyFiled 還有一些重要的可選參數,下面我們對它們依次進行介紹:
relate_name 與 ForeignKey 中的相同都用于反向查詢。
db_table 用于指定中間表的名稱,如果沒有提供,Django 會使用多對多字段的名稱和包含這張表的 Model 的名稱組合起來構成中間表的名稱,當然也會包含 index 前綴。
through 用于指定中間表,這個參數不需要設置,Django會自動生成隱式的 through Model。由于 Django可以生成自身默認的中間表,該參數可以讓用戶自己去控制表之間的關聯關系或者增加一些額外的信息。
3) 語法格式
class Author(models.Model):
...
class Book(models.Model):
...
authors = models.ManyToManyField(Author)
4) 多對多中間表
創建 Author 與 Book 之間多對多關聯關系,在 Author? Model 中添加如下代碼:
books=models.ManyToManyField(to="Book") #創建多對多映射關系
然后再執行數據庫遷移命令,我們可以執行以下命令可以查看 Django 執行 sql 語句:
python manage.py sqlmigrate index 0007_author_books
sql 語句如下所示:
CREATE TABLE `index_author_books` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `author_id` integer NOT NULL, `book_id` integer NOT NULL);
ALTER TABLE `index_author_books` ADD CONSTRAINT `index_author_books_author_id_2bfd143c_fk_index_author_id` FOREIGN KEY (`author_id`) REFERENCES `index_author` (`id`);
ALTER TABLE `index_author_books` ADD CONSTRAINT `index_author_books_book_id_1c280bc9_fk_index_book_id` FOREIGN KEY (`book_id`) REFERENCES `index_book` (`id`);
ALTER TABLE `index_author_books` ADD CONSTRAINT `index_author_books_author_id_book_id_b0dd3503_uniq` UNIQUE (`author_id`, `book_id`);
由 sql 語句可以看出,Django 默認隱式的創建了 index_author_books 表(Django 的命名規范),即維護關聯關系的中間表。這個表有三個字段分別是主鍵 id,與index_author 表關聯的 author_id,以及 index_book 表關聯的 book_id。同時為這兩個關聯 id 創建了外鍵約束(FORGIEN KEY),最后還為?index_author_books 表創建了唯一性約束 author_id 和 book_id。
上面介紹了 Django 自身默認創建中間表的過程,當然我們也可以自己建立中間表,然后通過 Author 表中 books 字段的 through 參數指向這張中間表。如果大家對于 MySQL 自建中間表或其它知識不熟悉,推薦學習本網站的《MySQL教程》來查漏補缺。
5) 實例應用
插入作者信息數據,如下所示:
author1=Author.objects.create(name="Luncy",email="123456@qq.com")
author2=Author.objects.create(name="Tom",email="456789@163.com")
因為書籍信息之前已經準備完畢,所以下面我們開始創建多對多映射關系,我們在 Django shell 進行如下操作:
author1.books.add(Book.objects.get(id="1"))
author1.books.add(Book.objects.get(id="2"))
author1.books.add(Book.objects.get(id="3"))
author2.books.add(Book.objects.get(id="1"))
author2.books.add(Book.objects.get(id="4"))
author2.books.add(Book.objects.get(id="5"))
author2.books.add(Book.objects.get(id="3"))
author2.books.add(Book.objects.get(id="6"))
author1.books.add(Book.objects.get(id="6"))
多對多關系在中間表插入數據需要使用 add() 方法,books 是對應的多對多字段。通過以上代碼就完成多對多關系的創建,最后在 MySQL 中查看多對多相關聯的三張數據表,如下所示:
#書籍信息表(index_book)
+----+---------+--------+-------+--------------+
| id | title | pub_id | price | retail_price |
+----+---------+--------+-------+--------------+
| 1 | Python | 8 | 59.00 | 59.00 |
| 2 | Redis | 8 | 25.00 | 25.00 |
| 3 | Java | 8 | 45.00 | 45.00 |
| 4 | Django | 9 | 65.00 | 65.00 |
| 5 | Flask | 9 | 45.00 | 45.00 |
| 6 | Tornado | 9 | 35.00 | 35.00 |
+----+---------+--------+-------+--------------+
#作家信息表(index_author)
+----+-------+----------------+
| id | name | email |
+----+-------+----------------+
| 1 | Luncy | 123456@qq.com |
| 2 | Tom | 456789@163.com |
+----+-------+----------------+
#中間表(index_author_books)
+----+-----------+---------+
| id | author_id | book_id |
+----+-----------+---------+
| 4 | 1 | 1 |
| 7 | 1 | 3 |
| 5 | 1 | 4 |
| 6 | 1 | 5 |
| 8 | 1 | 6 |
| 1 | 2 | 1 |
| 2 | 2 | 2 |
| 3 | 2 | 3 |
| 9 | 2 | 6 |
+----+-----------+---------+
本節用了較長的篇幅給大家講解了 Django 中數據表的關聯關系,它和 MySQL 的思想是一致的,只是 Django 提供了自己的一套方法,所以我們也要學會使用它,在后續章節我們將基于此節的內容介紹 Django QuerySet API 即與數據庫接口相關的表查詢、更新、刪除操作。
總結
以上是生活随笔為你收集整理的django orm级联_Django数据表关联关系映射(一对一、一对多、多对多)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: arduino电源接口直径多大_求助:A
- 下一篇: scrcpy设置快捷键_电脑端scrcp