Django 06. django框架模型之表關係ForeignKey,ManyToManyField與OneToOneField


簡介
       數據庫中表與表之間的關係,舉例詳解一對多、一對1、多對多關係,及表關係一些進階技巧。

1. 數據庫中表與表之間的關係  
 
    • 一對多,models.ForeignKey(ColorDic)
    • 一對一,models.OneToOneField(OneModel)
    • 多對多,authors = models.ManyToManyField(Author)

應用場景:python

      • 一對一:在某表中建立一行數據時,有一個單選的下拉框(下拉框中的內容被用過一次就消失了)。
        例如:與同事合做開發過程當中兩人都用到一某個表,這個表原有含10列數據,通過一段時間以後,發現10列沒法知足本身的需求,須要爲原來的表再添加5列數據,可是爲了避免影響同事的使用,可使用一對一關係設計表,新的表中只須要包含要新加的這5列數據便可。

      • 一對多:當一張表中建立一行數據時,有一個單選的下拉框(能夠被重複選擇)。
        例如:建立用戶信息時候,用戶信息中包含用戶類型(普通用戶、管理員、超級管理員),用戶與用戶類型就屬於一對多關係。一個用戶對應一種用戶類型,但一種用戶類型能夠包含多個用戶。

      • 多對多:在某表中建立一行數據時,有一個能夠多選的下拉框。
        例如:建立用戶信息,須要用戶選擇愛好,一個用戶能夠有多個愛好,一種愛好能夠被多個用戶選擇。

2. 舉例詳解
    例如,一本書由一家出版社出版,一家出版社能夠出版不少書。一本書由多個做者合寫,一個做者能夠寫不少書。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
 
class 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)
    #一本書能夠由多個做者合寫,一個做者能夠寫多本書,屬於多對多關係,用ManyToManyField
    authors = models.ManyToMany(Author)
    生成結果:
    
 一共生成了4張表:
 
web_author(做者表)


 web_publisher(出版社表)

 
web_book_authors(記錄book與author多對多關係表。多對多關係要藉助第三張表創建關係)

 
web_book(book表,其中pub_id體現書與出版社之間的一對多關係)


3. 表關係進階web

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, IntegrityError
 
class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)
    def __unicode__(self):
        return u"%s the place" % self.name
 
class 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.name
 
class 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")
相關文章
相關標籤/搜索