Django(15)外來鍵和表關係

Silent丿丶黑羽發表於2021-05-17

外來鍵刪除操作

如果一個模型使用了外來鍵。那麼在對方那個模型被刪掉後,該進行什麼樣的操作。可以通過on_delete來指定。可以指定的型別如下:

  1. CASCADE:級聯操作。如果外來鍵對應的那條資料被刪除了,那麼這條資料也會被刪除。
  2. PROTECT:受保護。即只要這條資料引用了外來鍵的那條資料,那麼就不能刪除外來鍵的那條資料。
  3. SET_NULL:設定為空。如果外來鍵的那條資料被刪除了,那麼在本條資料上就將這個欄位設定為空。如果設定這個選項,前提是要指定這個欄位可以為空
  4. SET_DEFAULT:設定預設值。如果外來鍵的那條資料被刪除了,那麼本條資料上就將這個欄位設定為預設值。如果設定這個選項,前提是要指定這個欄位一個預設值。
  5. SET():如果外來鍵的那條資料被刪除了。那麼將會獲取SET函式中的值來作為這個外來鍵的值。SET函式可以接收一個可以呼叫的物件(比如函式或者方法),如果是可以呼叫的物件,那麼會將這個物件呼叫後的結果作為值返回回去。
  6. DO_NOTHING:不採取任何行為。一切全看資料庫級別的約束。

注意:以上這些選項只是Django級別的,資料級別依舊是RESTRICT
 

表關係

表之間的關係都是通過外來鍵來進行關聯的。而表之間的關係,無非就是三種關係:一對一、一對多、多對多等。以下將討論一下三種關係的應用場景及其實現方式。
 

一對多

應用場景:比如文章和作者之間的關係。一個文章只能由一個作者編寫,但是一個作者可以寫多篇文章。文章和作者之間的關係就是典型的多對一的關係
實現方式:一對多,都是通過ForeignKey來實現的。

class User(models.Model):
    username = models.CharField(max_length=20)
    password = models.CharField(max_length=100)

class Article(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    author = models.ForeignKey("User",on_delete=models.CASCADE)

那麼以後在給Article物件指定category,就可以使用以下程式碼來完成:

article = Article(title='abc',content='123')
author = User(username='jkc',password='123456')
# 要先儲存到資料庫中
author.save()
article.author = author
article.save()

並且以後如果想要獲取某個種類下所有的文章,可以通過article_set來實現。示例程式碼如下:

user = User.objects.first()
# 獲取第一個使用者寫的所有文章
articles = user.article_set.all()
for article in articles:
    print(article)

 

一對一

  1. 在Django中一對一是通過models.OnetToOneField來實現的。這個OneToOneField其實本質上就是一個外來鍵,只不過這個外來鍵有一個唯一約束(unique key),來實現一對一。
  2. 以後如果想要反向引用,那麼是通過引用的模型的名字轉換為小寫的形式進行訪問。比如以下模型:
 class FrontUser(models.Model):
     username = models.CharField(max_length=200)

 class UserExtension(models.Model):
     school = models.CharField(max_length=100)
     user = models.OneToOneField("FrontUser",on_delete=models.CASCADE)

 # 通過userextension來訪問UserExtension物件
 user = FrontUser.objects.first()
 print(user.userextension)

UserExtension的物件,可以通過user來訪問到對應的user物件。並且FrontUser物件可以使用userextension來訪問對應的UserExtension物件。 如果不想使用Django預設的引用屬性名字。那麼可以在OneToOneField中新增一個related_name引數。示例程式碼如下:

 class FrontUser(models.Model):
     username = models.CharField(max_length=200)

 class UserExtension(models.Model):
     school = models.CharField(max_length=100)
     user = models.OneToOneField("FrontUser",on_delete=models.CASCADE,related_name='extension')

 # 通過extension來訪問到UserExtension物件
 user = FrontUser.objects.first()
 print(user.extension)

那麼以後就FrontUser的物件就可以通過extension屬性來訪問到對應的UserExtension物件。
 

多對多

  1. 應用場景:比如文章和標籤的關係。一篇文章可以有多個標籤,一個標籤可以被多個文章所引用。因此標籤和文章的關係是典型的多對多的關係。
  2. 實現方式:Django為這種多對多的實現提供了專門的Field。叫做ManyToManyField。還是拿文章和標籤為例進行講解。示例程式碼如下:
 class Article(models.Model):
     title = models.CharField(max_length=100)
     content = models.TextField()
     tags = models.ManyToManyField("Tag",related_name="articles")

 class Tag(models.Model):
     name = models.CharField(max_length=50)

在資料庫層面,實際上Django是為這種多對多的關係建立了一箇中間表。這個中間表分別定義了兩個外來鍵,引用到articletag兩張表的主鍵。
在我們使用多對多反向引用新增的時候,只能使用add這種新增方式,比如向文章中新增標籤,示例程式碼如下:

article = Article.objects.first()
tag = Tag(name="好看")
tag.save()
article.tag_set.add(tag)  # 向文章中新增標籤tag

 

相關文章