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")
相关文章
相关标签/搜索