Django ORM的继承关系
ORM中通常将对象引用映射到外键,但是对于继承,关系数据库中没有自然有效的方法来对应。从数据存储的角度来看,在映射继承关系时,可以采用几种方式(参考JPA中的InheritanceType.定义):
- 使用单个表,在JPA中称作SINGLE_TABLE。整个继承树共用一张表。使用唯一的表,包含所有基类和子类的字段。
- 每个具体类一张表,在JPA中称作TABLE_PER_CLASS。这种方式下,每张表都包含具体类和继承树上所有父类的字段。因为多个表中有重复字段,从整个继承树上来说,字段是冗余的。
- 每个类一张表,继承关系通过表的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的继承关系的更多相关文章
- Django的Model继承abstract,proxy,managed。。。
Django 中的 model 继承和 Python 中的类继承非常相似,只不过你要选择具体的实现方式:让父 model 拥有独立的数据库:还是让父 model 只包含基本的公共信息,而这些信息只能由 ...
- Django学习之十四:Django ORM继承关系
目录 Django ORM继承关系 1. SINGLE_TABLE(django好像不支持) 2. TABLE_PER_CLASS 3. JOINED 4. 代理继承 Django ORM继承关系 参 ...
- django ORM模型表的一对多、多对多关系、万能双下划线查询
一.外键使用 在 MySQL 中,如果使用InnoDB引擎,则支持外键约束.(另一种常用的MyIsam引擎不支持外键) 定义外键的语法为fieldname=models.ForeignKey(to_c ...
- Python学习---django之ORM语法[对象关系映射]180124
ORM语法[对象关系映射] ORM: 用面向对象的方式去操作数据库的创建表以及增删改查等操作. 优点:1 ORM使得我们的通用数据库交互变得简单易行,而且完全不用考虑该死的SQL语句.快速开发. 2 ...
- Django——Django中的QuerySet API 与ORM(对象关系映射)
首先名词解释. ORM: 对象关系映射(英语:Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型 ...
- Django框架之第六篇(模型层)--单表查询和必知必会13条、单表查询之双下划线、Django ORM常用字段和参数、关系字段
单表查询 补充一个知识点:在models.py建表是 create_time = models.DateField() 关键字参数: 1.auto_now:每次操作数据,都会自动刷新当前操作的时间 2 ...
- Django中多对多关系的orm表设计
作者的管理 1.设计表结构 出版社 书籍 作者 一个出版社出版多个书籍 1对多 书籍和作者的关系:一个作者写多本书,一本书可以是多个作者写.多对多 1)创建一张表,表中多对多的数据关系.使用 多对多 ...
- Django中ORM创建表关系
一:django中ORM创建表关系 ORM创建外键关系 1.表与表之间的关系 1.表与表之间的关系 一对多 一对一 多对多 2.操作目标条件: 图书表 出版社表 作者表 作者详情表 3.外键关联 一对 ...
- Django ORM模型的一点体会
作者:Vamei 出处:http://www.cnblogs.com/vamei 严禁转载. 使用Python的Django模型的话,一般都会用它自带的ORM(Object-relational ma ...
随机推荐
- 第三天Beta冲刺
团队作业Beta冲刺 项目 内容 这个作业属于哪个课程 任课教师博客主页链接 这个作业的要求在哪里 作业链接地址 团队名称 你们都是魔鬼吗 作业学习目标 (1)掌握软件黑盒测试技术:(2)学会编制软件 ...
- LINQ查询表达式(2) - 在 C# 中编写 LINQ 查询
在 C# 中编写 LINQ 查询 C# 中编写 LINQ 查询的三种方式: 使用查询语法. 使用方法语法. 组合使用查询语法和方法语法. // 查询语法 IEnumerable<int> ...
- 不安装Oracle客户端使用PLSQL Developer
一.下载 1.Oracle Instant Client: (需要安装 Visual Studio 2013 redistributable.) basic-windows.x64-18.5下载地址: ...
- oracle lock
数据库锁介绍: https://www.cnblogs.com/springsnow/p/9990295.html#_label2_0 总结1:查询oracle锁定的表: 1.锁相关表 SELECT ...
- 2019-2020-1 20199302《Linux内核原理与分析》第六周作业
一 .万能函数 1.过程抽象 (1)接口:指明模块要做什么,标识符/类型.函数等,.h ,函数调用者 (2)实现:指明模块如何完成接口,一个接口多个实现(可能),.c ,函数实现者 (3)函数签名:函 ...
- loj #6342. 跳一跳 期望dp
令 $f[i]$ 表示已经到达 $i$ 点,为了到大 $n$ 点还期望需要的时间,随便转移一下就行. 由于本题卡空间,要记得开滚动数组. #include <bits/stdc++.h> ...
- VIJOS PID221 / 烦人的幻灯片
暴力出奇迹,学长诚不欺我. PID221 / 烦人的幻灯片 2017-04-14 19:47:08 运行耗时:30 ms 运行内存:12292 KB 查看最后一次评测记录 题目描述 李教授于今天下午 ...
- github提示Permission denied (publickey),如何才能解决?
参考: https://my.oschina.net/u/1377923/blog/1822038 https://www.cnblogs.com/chjbbs/p/6637519.html
- golang 常见变成问题01
Golang常见编程问题 --语言简单 func CopyFile (dst, src string) (w int64, err error) { srcFile, err := os.Open ( ...
- TCP采用四次挥手关闭连接如图所示为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?
tcp四次挥手,由于TCP连接是全双工的,因此每个方向都必须单独进行关闭. 由于TCP连接是全双工的,因此每个方向都必须单独进行关闭.这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个 ...