簡介
數據庫中表與表之間的關系,舉例詳解一對多、一對一、多對多關系,及表關系一些進階技巧。
1. 數據庫中表與表之間的關系
- 一對多,models.ForeignKey(ColorDic)
- 一對一,models.OneToOneField(OneModel)
- 多對多,authors = models.ManyToManyField(Author)
應用場景:
- 一對一:在某表中創建一行數據時,有一個單選的下拉框(下拉框中的內容被用過一次就消失了)。
例如:與同事合作開發過程中兩人都用到一某個表,這個表原有含10列數據,經過一段時間之后,發現10列無法滿足自己的需求,需要為原來的表再添加5列數據,但是為了不影響同事的使用,可以使用一對一關系設計表,新的表中只需要包含要新加的這5列數據即可。
- 一對多:當一張表中創建一行數據時,有一個單選的下拉框(可以被重復選擇)。
例如:創建用戶信息時候,用戶信息中包含用戶類型(普通用戶、管理員、超級管理員),用戶與用戶類型就屬於一對多關系。一個用戶對應一種用戶類型,但一種用戶類型可以包含多個用戶。
- 多對多:在某表中創建一行數據時,有一個可以多選的下拉框。
例如:創建用戶信息,需要用戶選擇愛好,一個用戶可以有多個愛好,一種愛好可以被多個用戶選擇。
2. 舉例詳解
例如,一本書由一家出版社出版,一家出版社可以出版很多書。一本書由多個作者合寫,一個作者可以寫很多書。
#!/usr/bin/env python# -*- coding: utf-8 -*-from __future__ import unicode_literalsfrom django.db import modelsclass Author(models.Model):name = models.CharField(max_length=30)class Publisher(models.Model):name = models.CharField(max_length=50)class Book(models.Model):name = models.CharField(max_length=50)#一本書由一家出版社發布,一個出版社發布多本書。屬於一對多關系,用ForeignKey()pub = models.ForeignKey(Publisher)#一本書可以由多個作者合寫,一個作者可以寫多本書,屬於多對多關系,用ManyToManyFieldauthors = models.ManyToMany(Author)
生成結果:
一共生成了4張表:
web_author(作者表)
web_publisher(出版社表)
web_book_authors(記錄book與author多對多關系表。多對多關系要借助第三張表建立關系)
web_book(book表,其中pub_id體現書與出版社之間的一對多關系)
3. 表關系進階
1. 關聯尚未定義的Model
class Book(models.Model):name = models.CharField(max_length = 50)#如果Publisher與Author在Book后面定義,需要使用model 的名稱,而不是使用 model 對象本身pub = models.ForeignKey('Publisher')authors = models.ManyToManyField('Author')class Publisher(models.Model):name = models. CharField (max_length = 50)class Author(models.Model):name = models.CharField(max_length = 30)
2. Model關聯自身
1) Model可以與自身做多對一關系
class People(models.Model):name = models.CharField(max_length = 30)leader = models.ForeignKey('self', blank=True, null=True)
說明:一個領導有多個下屬,一個下屬對應一個直接領導,同時領導也是領導的下屬。就屬於多對一關系,且需要與自身做多對一關系。且注 意,設計這表時要設置blank=True和null=True.2) Model可以與自身做多對多關系
class Person(models.Model):friends = models.ManyToManyField('self')
說明:1. 你是我的朋友,我可以有多個朋友,我也是你的朋友,你也可以有多個朋友,這就屬於朋友間的多對多關系。
2. 會生成兩張表,一張person表,只含有id和name。一張person_friends表含有id,from_person_id,to_person_id
person_friends:

3. OneToOneField
class OneToOneField(othermodel[, parent_link=False, **options])
用來定義一對一關系。籠統地講,它與聲明了 unique=True 的 ForeignKey 非常相似,不同的是使用反向關聯的時候,得到的不是一個對象列表,而是一個單獨的對象。在某個 model 擴展自另一個 model 時,這個字段是非常有用的;例如: 多表繼承 (Multi-tableinheritance) 就是通過在子 model 中添加一個指向父 model 的一對一關聯而實現的。必須給該字段一個參數:被關聯的 model 類。工作方式和 ForeignKey 一樣,連遞歸關聯 (recursive) 和 延后關聯 (lazy) 都一樣。 此外,OneToOneField 接受 ForeignKey 可接受的參數,只有一個參數是 OnetoOneField 專有的:OneToOneField.parent_link, 如果為 True,並且作用於繼承自某個父 model 的子 model 上(這里不能是延后繼承,父 model 必須真實存在 ),那么該字段就會變成指向父類實例的引用(或者叫鏈接), 而不是象其他OneToOneField 那樣用於擴展父類並繼承父類屬性。
from django.db import models, transaction, IntegrityErrorclass Place(models.Model):name = models.CharField(max_length=50)address = models.CharField(max_length=80)def __unicode__(self):return u"%s the place" % self.nameclass Restaurant(models.Model):place = models.OneToOneField(Place, primary_key=True)serves_hot_dogs = models.BooleanField()serves_pizza = models.BooleanField()def __unicode__(self):return u"%s the restaurant" % self.place.nameclass Waiter(models.Model):restaurant = models.ForeignKey(Restaurant)name = models.CharField(max_length=50)def __unicode__(self):return u"%s the waiter at %s" % (self.name, self.restaurant)
使用反向關聯的時候,得到的不是一個對象列表,而是一個單獨的對象:
>>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton')>>> p1.save()>>> r = Restaurant(place=p1, serves_hot_dogs=True, serves_pizza=False)>>> r.save()>>> p1.restaurant<Restaurant: Demon Dogs the restaurant>>>> Place.objects.get(restaurant__place__name__startswith="Demon")<Place: Demon Dogs the place>>>> Waiter.objects.filter(restaurant__place__name__startswith="Demon")