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 ...
随机推荐
- test20190803 夏令营NOIP训练19
60+100+0=160 贪婪大陆 面对蚂蚁们的疯狂进攻,小FF的Tower defence宣告失败--人类被蚂蚁们逼到了Greed Island上的一个海湾.现在,小FF的后方是一望无际的大海, 前 ...
- LG2664 树上游戏
树上游戏 题目描述 lrb有一棵树,树的每个节点有个颜色.给一个长度为n的颜色序列,定义s(i,j) 为i 到j 的颜色数量.以及 $$sum_i=\sum_{j=1}^ns(i,j)$$ 现在他想让 ...
- oracle 查询月份
①:select substr(to_char(sysdate,'yyyy-mm-dd'),6,2) from dual; ②:select to_char(sysdate,'MM') from du ...
- 向指定URL发送GET和POST请求
package com.sinosoft.ap.wj.common.util; import java.io.BufferedReader;import java.io.IOException;imp ...
- char[] byte[] string
C# byte 和 char 可以认为是等价的.但是在文本显示的时候有差异. char 占两个字节,unicode字符 1.内存转换: char转化为byte: public static byte ...
- Centos7 docker pull速度特别慢
vim /etc/docker/daemon.json { "registry-mirrors" : ["https://docker.mirrors.ustc.edu. ...
- Kubernetes 学习7 Pod控制器应用进阶2
一.容器探测器 1.所谓的容器探测无非就是我们在里面设置了一些探针,或者称之为传感器来获取相应的数据作为判定其存活与否或就绪与否的标准,目前k8s所支持的存活性和就绪性探测方式都是一样的. 2.k8s ...
- 018_Python3 模块
在前面的几个章节中我们脚本上是用 python 解释器来编程,如果你从 Python 解释器退出再进入,那么你定义的所有的方法和变量就都消失了. 为此 Python 提供了一个办法,把这些定义存放在文 ...
- java对接微信小程序
https://www.cnblogs.com/lyn20141231/p/11210372.html https://blog.csdn.net/sinat_29039125/article/det ...
- web之大文件断点续传
之前仿造uploadify写了一个HTML5版的文件上传插件,没看过的朋友可以点此先看一下~得到了不少朋友的好评,我自己也用在了项目中,不论是用户头像上传,还是各种媒体文件的上传,以及各种个性的业务需 ...