當使用Django進行數(shù)據(jù)庫操作時,F(xiàn)oreignKey(外鍵)是一種非常有用的字段類型。它允許在數(shù)據(jù)庫表之間創(chuàng)建關(guān)聯(lián)關(guān)系,類似于其他數(shù)據(jù)庫系統(tǒng)中的外鍵概念。通過ForeignKey字段,我們可以建立一個模型與另一個模型的一對多關(guān)系。
以下是一個實際例子,使用ForeignKey字段在Django中創(chuàng)建一對多關(guān)系,初學者可以通過這個實際例子去仔細觀察數(shù)據(jù)表“一對多”關(guān)系是怎么一回事兒。
假設我們正在開發(fā)一個博客應用程序,其中有兩個主要的模型:作者(Author)和文章(Post)。一個作者可以有多篇文章,而一篇文章只能由一個作者撰寫。在這種情況下,我們可以使用ForeignKey字段將文章與作者關(guān)聯(lián)起來。
首先,讓我們創(chuàng)建Author模型和Post模型:
from django.db import models
# Create your models here.
class Author(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
writer = models.ForeignKey(Author, on_delete=models.CASCADE)
def __str__(self):
return self.title
在上述代碼中,我們定義了Author模型和Post模型。Post模型中的writer
字段是一個ForeignKey字段,它將Post模型與Author模型相關(guān)聯(lián)。on_delete=models.CASCADE
參數(shù)表示當關(guān)聯(lián)的作者被刪除時,與該作者關(guān)聯(lián)的所有文章也將被刪除。
接下來,我們可以使用這些模型創(chuàng)建數(shù)據(jù)庫表:
python manage.py makemigrations
python manage.py migrate
現(xiàn)在我們已經(jīng)創(chuàng)建了Author和Post表,我們用下面的代碼來演示數(shù)據(jù)表“一對多”關(guān)系的操作及對數(shù)據(jù)表的影響。
import os
import django
# 設置Dango運行時需要的環(huán)境變量DJANGO_SETTINGS_MODULE
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myshop.settings')
# 加載Django的設置
django.setup()
# 導入模型
from app1.models import Author, Post
# 創(chuàng)建一個作者
author1 = Author(name='wenhao')
author1.save()
# 創(chuàng)建一篇文章,并將其與剛才創(chuàng)建的作者相關(guān)聯(lián)
post1 = Post(title='First Post', content='Hello, World!', writer=author1)
post1.save()
# 再創(chuàng)建一篇文章,也將其與剛才創(chuàng)建的作者相關(guān)聯(lián)
post2 = Post(title='My love', content='I love wang hong', writer=author1)
post2.save()
# 獲取一個作者的所有文章
author_get = Author.objects.get(name='wenhao')
posts_all = author_get.post_set.all()
for post in posts_all:
print(post)
在上面的代碼中,作者“wenhao”發(fā)表了兩篇文章,文章的title分別為’First Post’和’My love’,通過Post模型的一對多成員writer關(guān)聯(lián)到表 Author。
如果要理解語句posts_all = author_get.post_set.all()
中的post_set(),請參看我的另一篇博文,鏈接:https://blog.csdn.net/wenhao_ir/article/details/131668597
上面的代碼運行結(jié)果如下:
可見作者“wenhao”對應的兩篇文章的標題被打印出來了。
這里要多問一句,為什么內(nèi)容沒被打印出來呢?
請注意數(shù)據(jù)表模型中定義的下面語句:
def __str__(self):
return self.title
并結(jié)合Python的“魔術(shù)方法“(magic method)或“特殊方法“(special method)去理解這個問題,關(guān)于Python的“魔術(shù)方法“(magic method)或“特殊方法“(special method),請參見鏈接:https://blog.csdn.net/wenhao_ir/article/details/131395984
我們再去觀察一下數(shù)據(jù)表中的內(nèi)容,如下:
大家可以仔細觀察下這兩張表的內(nèi)容,看下Author是怎樣和Post進行一對多關(guān)聯(lián)的。
從上面的數(shù)據(jù)庫截圖中可以看出,在表 app1_post中,外鍵字段的名字為 writer_id,而不是想像中的 writer,這一點要注意,其值就是作者wenhao在表app_author中的id字段。
顯然,光憑數(shù)據(jù)表里的數(shù)據(jù),是無法知道字段表 app1_post中的writer_id是指向表app_author中的數(shù)據(jù),Django肯定在另外的地方記錄下了這種對應關(guān)系,記錄下這種對應關(guān)系的表叫“中間關(guān)系表”,這個“中間關(guān)系表”并沒有在數(shù)據(jù)庫中,目前昊虹君也不知道具體在哪里。不過在Django的某個地方,肯定存在著一個“中間關(guān)系表”,它的內(nèi)容如下:
writer_set→Author
提問:_set 是怎么來的?
答:從writer映射到模型Author 的關(guān)系在數(shù)據(jù)庫中叫做反向關(guān)系,writer_set稱為反向關(guān)系名,即related_name,如果不指定反向關(guān)系名,統(tǒng)就會以"字段名_set"的格式作為其默認反向關(guān)系名。
顯然,如果模型中,有多個“一對多”或“多對多”關(guān)系時,相應的字段名不能相同,否則會引起沖突。為什么?舉個例子,假如另一個模型中也有一個一對多的關(guān)系,這個一對多的關(guān)系指向模型Book,但是這個一對多的關(guān)系的字段名也為writer,那么“中間關(guān)系表”中就會存在一條下面這樣的反向關(guān)系記錄:
writer_set→Book
所以,“中間關(guān)系表”的內(nèi)容如下:
writer_set→Author
writer_set→Book
這樣,通過中間關(guān)系表就無法分清楚到底是哪個writer與Author模型相對應,又是哪個writer與Book模型相對應。
如果不能避免字段名字的相同,就要使用相關(guān)名稱參數(shù)(related_name)來為其在中間關(guān)系表中指定反向關(guān)系名,比如:
writer = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='blogs_writer')
writer = models.ForeignKey(Book, on_delete=models.CASCADE, related_name='book_writer')
經(jīng)上面的兩條代碼指定反向關(guān)系名,便沒有沖突了。
并且用related_name參數(shù)指定反向關(guān)系名后,就可以用這個反向關(guān)系名來訪問相應的字段了,比如下面這個示例:
# 獲取一個作者的所有文章
author_get = Author.objects.get(name='wenhao')
posts_all = author_get.blogs_writer.all()
for post in posts_all:
print(post)
運行上面的代碼,可得到下面的結(jié)果:
在建立一對多關(guān)系或多對多關(guān)系時,建議大家指定不容易重復的反向關(guān)系名,這樣可以提高代碼的健壯性。文章來源:http://www.zghlxwxcb.cn/news/detail-519853.html
擴展閱讀:
Django中使用反向關(guān)系名稱(related_name)解決由“多對多”關(guān)系引起的字段名字沖突問題引起的遷移命令報錯。文章來源地址http://www.zghlxwxcb.cn/news/detail-519853.html
到了這里,關(guān)于通過一個實際例子說明Django中的數(shù)據(jù)庫操作方法法ForeignKey()的用法【數(shù)據(jù)表“一對多”關(guān)系】的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!