ORM中通常将对象引用映射到外键,但是对于继承,关系数据库中没有自然有效的方法来对应。从数据存储的角度来看,在映射继承关系时,可以采用几种方式(参考JPA中的InheritanceType.定义):

  1. 使用单个表,在JPA中称作SINGLE_TABLE。整个继承树共用一张表。使用唯一的表,包含所有基类和子类的字段。
  2. 每个具体类一张表,在JPA中称作TABLE_PER_CLASS。这种方式下,每张表都包含具体类和继承树上所有父类的字段。因为多个表中有重复字段,从整个继承树上来说,字段是冗余的。
  3. 每个类一张表,继承关系通过表的JOIN操作来表示。在JPA中称作JOINED。这种方式下,每个表只包含类中定义的字段,不存在字段冗余,但是要同时操作子类和所有父类所对应的表。

Django的ORM也支持上述三种继承策略,同时,得益于python的动态特性,还支持代理模型和多重继承关系的映射。

JOINED映射

如果在Django中实现了Model的继承关系,如下:

from django.db import models

class Person(models.Model):
name = models.CharField(maxlength=10) class Man(Person):
job = models.CharField(maxlength=20) class Woman(Person):
makeup = models.CharField(maxlength=20)

则使用manage.py执行sqlall命令时,会看到这样的结果:

CREATE TABLE "uom_person" (
"id" integer NOT NULL PRIMARY KEY,
"name" varchar(10) NOT NULL
)
; CREATE TABLE "uom_man" (
"person_ptr_id" integer NOT NULL PRIMARY KEY REFERENCES "uom_person" ("id"),
"job" varchar(20) NOT NULL
)
; CREATE TABLE "uom_woman" (
"person_ptr_id" integer NOT NULL PRIMARY KEY REFERENCES "uom_person" ("id"),
"makeup" varchar(20) NOT NULL
)
;

可见,Django ORM中默认使用JOINED方式来实现继承关系的映射。

TABLE_PER_CLASS映射

如果要实现每个具体类一张表,只需要将父类指定为抽象类(abstract),这样就不会创建父类对应的表,而将父类的字段复制到子类中去映射。如下:

from django.db import models

class Person(models.Model):
name = models.CharField(max_length=10) class Meta:
abstract = True class Man(Person):
job = models.CharField(max_length=20) class Woman(Person):
makeup = models.CharField(max_length=20)

sqlall 的结果:

CREATE TABLE "uom_man" (
"id" integer NOT NULL PRIMARY KEY,
"name" varchar(10) NOT NULL,
"job" varchar(20) NOT NULL
)
; CREATE TABLE "uom_woman" (
"id" integer NOT NULL PRIMARY KEY,
"name" varchar(10) NOT NULL,
"makeup" varchar(20) NOT NULL
)
;

将父类声明为abstract时,该类将没有objects属性,也就是说没有Manager方法,所有无法进行数据操作,只有子类才能进行。

SINGLE_TABLE映射

在TABLE_PER_CLASS的基础上,如果进一步指定子类的映射表名与父类的相同,则子类和父类将映射到同一张表,对所有的子类都这样指定,就可以实现SINGLE—_TABLE映射:

from django.db import models

class Person(models.Model):
name = models.CharField(max_length=10)
class Meta:
abstract = True class Man(Person):
job = models.CharField(max_length=20)
class Meta:
db_table = 'oum_person' class Woman(User):
makeup = models.CharField(max_length=20)

sqlall 的结果:

CREATE TABLE "oum_person" (
"id" integer NOT NULL PRIMARY KEY,
"name" varchar(10) NOT NULL,
"job" varchar(20) NOT NULL
)
; CREATE TABLE "uom_woman" (
"user_ptr_id" integer NOT NULL PRIMARY KEY,
"makeup" varchar(20) NOT NULL
)
;

上面的例子中只指定了一个子类,可以看出因为是在子类上指定,所以Django ORM更加灵活,可以控制单个子类的映射方式,从而实现任意的映射结构。

代理模型

有这样一种常见的场景:使用某些库(lib)中的类,只是想扩展一些方法,而不想改变其数据存储结构。在Python中,可以通过在Meta类中增加约束proxy=True来实现。此时“子类”称为“父类”的代理类,子类中只能增加方法,而不能增加属性。比如上面的例子中,如果希望Person继承Django自带的User类,又不希望破坏User类的数据存储,则可以指定Person的proxy=True:

from django.db import models
from django.contrib.auth.models import User class Person(User):
# name = models.CharField(max_length=10)
class Meta:
proxy = True def do_something(self):
... class Man(Person):
job = models.CharField(max_length=20) class Woman(Person):
makeup = models.CharField(max_length=20)

sqlall的结果为:

CREATE TABLE "uom_man" (
"user_ptr_id" integer NOT NULL PRIMARY KEY,
"job" varchar(20) NOT NULL
)
; CREATE TABLE "uom_woman" (
"user_ptr_id" integer NOT NULL PRIMARY KEY,
"makeup" varchar(20) NOT NULL
)
;

多重继承

python支持多重继承,尽管在Model层不推荐使用多重继承,但Django的ORM还是支持这样的使用方式:

class Mixin1(models.Model):
attr1 = models.CharField(max_length=10)
class Mixin2(models.Model):
attr1 = models.CharField(max_length=10)
class Multiple(Mixin1,Mixin2):
attr3 = models.CharField(max_length=10)

sqlall的结果是:

CREATE TABLE "uom_mixin1" (
"id" integer NOT NULL PRIMARY KEY,
"attr1" varchar(10) NOT NULL
)
; CREATE TABLE "uom_mixin2" (
"id" integer NOT NULL PRIMARY KEY,
"attr1" varchar(10) NOT NULL
)
; CREATE TABLE "uom_multiple" (
"mixin2_ptr_id" integer NOT NULL UNIQUE REFERENCES "uom_mixin2" ("id"),
"mixin1_ptr_id" integer NOT NULL PRIMARY KEY REFERENCES "uom_mixin1" ("id"),
"attr3" varchar(10) NOT NULL
)
;

多重继承的时候,子类的ORM映射会选择第一个父类作为主键管理,其他的父类作为一般的外键管理。

小结

Django ORM在映射继承关系时非常灵活,不仅能够实现JPA约定的SINGLE_TABLE、TABLE_PER_CLASS、JOINED三种方式,还可以灵活的自定义;甚至通过python的动态语言特性,支持代理模型和多重继承的功能。但是正因为灵活,所以在使用的时候一定要非常注意,通过manage.py的sqllall功能,观察产生的sql语句,可以验证继承的实现机制,避免带来意想不到的问题。

Django ORM的继承关系的更多相关文章

  1. Django的Model继承abstract,proxy,managed。。。

    Django 中的 model 继承和 Python 中的类继承非常相似,只不过你要选择具体的实现方式:让父 model 拥有独立的数据库:还是让父 model 只包含基本的公共信息,而这些信息只能由 ...

  2. Django学习之十四:Django ORM继承关系

    目录 Django ORM继承关系 1. SINGLE_TABLE(django好像不支持) 2. TABLE_PER_CLASS 3. JOINED 4. 代理继承 Django ORM继承关系 参 ...

  3. django ORM模型表的一对多、多对多关系、万能双下划线查询

    一.外键使用 在 MySQL 中,如果使用InnoDB引擎,则支持外键约束.(另一种常用的MyIsam引擎不支持外键) 定义外键的语法为fieldname=models.ForeignKey(to_c ...

  4. Python学习---django之ORM语法[对象关系映射]180124

    ORM语法[对象关系映射] ORM: 用面向对象的方式去操作数据库的创建表以及增删改查等操作. 优点:1 ORM使得我们的通用数据库交互变得简单易行,而且完全不用考虑该死的SQL语句.快速开发. 2 ...

  5. Django——Django中的QuerySet API 与ORM(对象关系映射)

    首先名词解释. ORM: 对象关系映射(英语:Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型 ...

  6. Django框架之第六篇(模型层)--单表查询和必知必会13条、单表查询之双下划线、Django ORM常用字段和参数、关系字段

    单表查询 补充一个知识点:在models.py建表是 create_time = models.DateField() 关键字参数: 1.auto_now:每次操作数据,都会自动刷新当前操作的时间 2 ...

  7. Django中多对多关系的orm表设计

    作者的管理 1.设计表结构 出版社 书籍 作者 一个出版社出版多个书籍  1对多 书籍和作者的关系:一个作者写多本书,一本书可以是多个作者写.多对多 1)创建一张表,表中多对多的数据关系.使用 多对多 ...

  8. Django中ORM创建表关系

    一:django中ORM创建表关系 ORM创建外键关系 1.表与表之间的关系 1.表与表之间的关系 一对多 一对一 多对多 2.操作目标条件: 图书表 出版社表 作者表 作者详情表 3.外键关联 一对 ...

  9. Django ORM模型的一点体会

    作者:Vamei 出处:http://www.cnblogs.com/vamei 严禁转载. 使用Python的Django模型的话,一般都会用它自带的ORM(Object-relational ma ...

随机推荐

  1. 团队作业第六次—团队Github实战训练(追光的人)

    所属课程 软件工程1916 作业要求 团队作业第六次-团队Github实战训练 团队名称 追光的人 作业目标 搭建一个相对公平公正的抽奖系统,根据QQ聊天记录,完成从统计参与抽奖人员颁布抽奖结果的基本 ...

  2. CH6302 雨天的尾巴

    6302 雨天的尾巴 0x60「图论」例题 背景 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了 ...

  3. 结构型模式(五) 外观模式(Facade)

    一.动机(Motivate) 在软件系统开发的过程中,当组件的客户(即外部接口,或客户程序)和组件中各种复杂的子系统有了过多的耦合,随着外部客户程序和各子系统的演化,这种过多的耦合面临很多变化的挑战. ...

  4. drf框架 - 过滤组件 | 分页组件 | 过滤器插件

    drf框架 接口过滤条件 群查接口各种筛选组件数据准备 models.py class Car(models.Model): name = models.CharField(max_length=16 ...

  5. cookies插件 , axios插件,element-ui 插件

    vue-cookie插件 安装 >: cnpm install vue-cookies main.js配置 // 第一种方式 import cookies from 'vue-cookies' ...

  6. BeautifulSoup模板简单应用-提取html指定数据(api_name/api_method/api_path,请求body/请求header/pagam参数)

    from bs4 import BeautifulSoup import re import os.path import itertools name='newcrm' source_file_pa ...

  7. 一般spring配置上下文

    <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://mave ...

  8. 编程判断输入的字符是否为‘y’或‘Y’,若是,则输出‘yes’,否则输出‘no’

    #include<stdio.h>void main(){ char ch; ch=getchar(); ch == 'y' || ch == 'Y' ? printf("yes ...

  9. PostgreSQL 恢复大法 - 恢复部分数据库、跳过坏块、修复无法启动的数据库

    转载自:https://yq.aliyun.com/articles/582880 背景 一个较大的数据库,如何只恢复一部分数据(例如只恢复某个DB). 如果访问有坏块的表. 如何从无法启动的数据库中 ...

  10. VSCompile

    VS2012加载失败 No exports were found that match the constraint 开始->运行->devenv.exe /resetuserdata-& ...