Django学习之十四:Django ORM继承关系
Django ORM继承关系
参考:https://www.cnblogs.com/holbrook/archive/2012/03/18/2405036.html
因为关系数据库是没有自然有效的方法来表示表与表之间的继承关系。而model layer 是用类来表示表,而类是面向对象的范畴,继承是它的一大特性。自然可以使用model class 通过继承来表示它们之间的关系,但是要映射到关系数据库应该是怎样表示。这就得从数据库存储的角度来看,大牛们采用了几种在数据库中映射继承关系的方式:主要三种
single_table/table_per_class/joined 主要三种
由于python语言的动态性,python类是可以进行多重继承关系,那么还有多重继承关系的映射。
最后还有一种代理模型继承。
对于抽象model的定义,必须在其内嵌类中指定一个abstract = True的metadata,需要注意的是,虽然subclass继承了抽象类,同时继承了class meta内嵌类的内容;但是有些内嵌类中的属性是不会被继承的,如对于abstract = True 这个metadata是没有继承的。也就是说在构建subclass 的时候,会将abstract 设置为Flase。如果要构建一个抽象类继承自一个抽象类, 那么就需要在子抽象类中显示的声明abstract = True。相同的如db_table也不会继承到子类中,子类需要自己声明。
因为orm的可继承和三种继承方式的特点,那么一个model映射一个数据库表的说法就错了。抽象model是不会映射任何数据库表的。
1. SINGLE_TABLE(django好像不支持)
使用单个表,且数据库中只有一个映射表,这个表就代表了整个继承树,继承树中的多个子类model只会操作自己新增的字段,不会因为整个继承树使用一个表而能操作其它非自己的字段;这种就是一表收揽所有字段,字段虽然没有冗余了,但是数据父类数据对象是冗余的。同一个父对象有多个子对象。
single_table 在model layer上定义就是父类和子类
from django.db import models
class Vehicle(models.Model): # 抽象类在migration时不会创建表
name = models.CharField(max_length=32)
class Meta:
abstract = True
class Car(Vehicle):
Color = models.CharField(max_length=32)
class Meta:
db_table = 'mbook_vehicle'
class Bike(Vehicle):
Weight = models.IntegerField()
class Meta:
db_table = 'mbook_vehicle'
2. TABLE_PER_CLASS
有字段冗余,每个类一张表,父类是抽象类不创建父类映射的表,而是将父类的字段复制到子类映射表中去。
from django.db import models
class Animal(models.Model):
name = models.CharField(max_length=32)
class Meta:
abstract = True
class Dog(Animal):
Color = models.CharField(max_length=32)
class Bird(Animal):
Size = models.CharField(max_length=32)
使用python manage.py sqlmigrate mbook 0005 查看sql如下:
BEGIN;
--
-- Create model Bird
--
CREATE TABLE `mbook_bird` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(32) NOT NULL, `Size` varchar(32) NOT NULL);
--
-- Create model Dog
--
CREATE TABLE `mbook_dog` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(32) NOT NULL, `Color` varchar(32) NOT NULL);
COMMIT;
-- 只创建了具体类表,抽象父类是没有创建的。并且name字段是冗余的。
因为Animal类是抽象类,所以没有objects属性,即没有manager管理器,所以不能操作数据对象,映射表也没创建,自然也不能操作数据。只有子类才能操作。
抽象继承操作没什么说的,就是操作继承的具体子类就可以了。这个是用的比较多的。
3. JOINED
没有冗余,每个类一张表,要同时操作父表和子表
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=10)
class Man(Person):
job = models.CharField(max_length=20)
class Woman(Person):
makeup = models.CharField(max_length=20)
使用python manage.py sqlmigrate mbook 0004 可以看到创建表的sql语句
BEGIN;
--
-- Create model Person
--
CREATE TABLE `mbook_person` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(32) NOT NULL); -- id是django自动生成的
--
-- Create model Man
--
CREATE TABLE `mbook_man` (`person_ptr_id` integer NOT NULL PRIMARY KEY, `job` varchar(32) NOT NULL);
--
-- Create model Woman
--
CREATE TABLE `mbook_woman` (`person_ptr_id` integer NOT NULL PRIMARY KEY, `makeup` varchar(32) NOT NULL);
ALTER TABLE `mbook_man` ADD CONSTRAINT `mbook_man_person_ptr_id_9ab049ad_fk_mbook_person_id` FOREIGN KEY (`person_ptr_id`) REFERENCES `mbook_person` (`id`);
-- 添加一个外键
ALTER TABLE `mbook_woman` ADD CONSTRAINT `mbook_woman_person_ptr_id_67db6679_fk_mbook_person_id` FOREIGN KEY (`person_ptr_id`) REFERENCES `mbook_person` (`id`);
COMMIT;
这种,在子类没有新建父类的字段,但是子类可以使用父类的字段,创建子类的数据时,因为子类是继承自父类,在python-level,子类是有父类的字段的,所以子类在创建新实例是,在python-level看上去是在自己的表中添加了,其实是操作了了两个表,即子类自己映射的表中,和其继承的父类表中都添加了数据。所以叫做多表继承,也就是子类和父类映射的表都会参与继承。实质是添加了onetoone的关系。
下面是数据操作:
1. 通过Man创建数据,相应Person中是否有数据
>>> m = Man.objects.create(job='programmer')
mbook_man:
1 programmer
mbook_person:
1
两个表都有数据,但是由于没有指定name,所以person表没有name.
从效果,可以看出应用途径,多表继承字段不冗余,也达到了继承表的效果。
2. 通过删除Man记录,
>>> m.delete()
(2, {'mbook.Man': 1, 'mbook.Person': 1})
结果是两个表的数据都被删除了;进一不说明多表继承是有效的,继承的效果在python层面和数据库层面得到了理想相同的效果。
4. 代理继承
也就是一个model继承自一个具体类,但是只是一个代理类,也就是通过这个继承出来的代理类,来操作父类,这个代理类只需要在class meta中添加proxy = True 的metadata就可以。
出现代理类这种继承,是有这样一个需求,就是:因为多表继承,子类会创建表,现在需求是不想创建新的表,只是在子类中添加在python-level的一些行为(因为不能去修改父类,在父类中添加新的python层面行为),所以只能通过继承来添加,但是又不用子类有新的field字段,也不用创建一个新的子类映射的表。基于这种需求,就出现了,代理继承模式,就是像抽象继承的的反过程(抽象类没表,子类具体类有表),代理是父类是具体类有表,代理继承的类是没有表的,只在python代码层面新增了方法,而不用代理子类创建新的表。
和抽象不同的是,抽象类是没有manager的,是不能够通过抽象类访问数据库具体数据的。
而代理类则不同了,它是有manager的,是可以通过manager操作它所代理的父类具体类中的数据的。
代理继承的好处:
你可以在代理 model 中改变默认的排序设置和默认的 manager ,更不会对原始 model 产生影响。
如代理类 设置排序,这样问代理类获取数据是排序的结果;使用具体类父类获取数据得到的非排序结果;这个应用是非常常见的,在不改变model的情况下。
代理类的限制:
- 代理 model 必须继承自一个非抽象基类
- 你不能继承自多个非抽象基类,这是因为一个代理 model 不能连接不同的数据表
- 代理 model 也可以继承任意多个抽象基类,但前提是它们没有定义任何 model 字段
代理类的manager
- 如果你没有在代理 model 中定义任何 manager ,代理 model 就会从父类中继承 manager
- 如果你在代理 model 中定义了一个 manager ,它就会变成默认的 manager ,不过定义在父类中的 manager 仍是有效的
Django学习之十四:Django ORM继承关系的更多相关文章
- Django学习笔记〇四——数据库ORM的使用(有待修改)
Django框架基本上都是要和数据库结合使用的,我在以前讲过SQLAlchemy框架的使用,Django支持的不是SQLAlchemy,但是也内嵌了ORM框架,可以不需要直接面对数据库编程,而可以通过 ...
- Django学习之十: staticfile 静态文件
目录 Django学习之十: staticfile 静态文件 理解阐述 静态文件 Django对静态文件的处理 其它方面 总结 Django学习之十: staticfile 静态文件 理解阐述 ...
- “全栈2019”Java第四十四章:继承
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例
python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例 新浪爱彩双色球开奖数据URL:http://zst.aicai.com/ssq/openInfo/ 最终输出结果格 ...
- Linux学习之十四、管线命令
Linux学习之十四.管线命令 地址:http://vbird.dic.ksu.edu.tw/linux_basic/0320bash_6.php
- 风炫安全WEB安全学习第二十四节课 利用XSS钓鱼攻击
风炫安全WEB安全学习第二十四节课 利用XSS钓鱼攻击 XSS钓鱼攻击 HTTP Basic Authentication认证 大家在登录网站的时候,大部分时候是通过一个表单提交登录信息. 但是有时候 ...
- Django框架(十四)-- forms组件、局部钩子、全局钩子
一.什么是forms组件 forms组件就是一个类,可以检测前端传来的数据,是否合法. 例如,前端传来的邮箱数据,判断邮件格式对不对,用户名中不能以什么开头,等等 二.forms组件的使用 1.使用语 ...
- Django学习(三)---Models(ORM框架)
1) Django 中Models是与数据库相关的,与数据库相关的代码一般写在 models.py中,Django 支持 sqlite3, MySQL, PostgreSQL等数据库,只需要在sett ...
- Django学习笔记之Models与ORM操作
一.ORM增加 from django.db import models class Publisher(models.Model): name = models.CharField(max_leng ...
随机推荐
- NLP之词向量
1.对词用独热编码进行表示的缺点 向量的维度会随着句子中词的类型的增大而增大,最后可能会造成维度灾难2.任意两个词之间都是孤立的,仅仅将词符号化,不包含任何语义信息,根本无法表示出在语义层面上词与词之 ...
- BERT、ERNIE以及XLNet学习记录
主要是对 BERT: Pre-training of Deep Bidirectional Transformers for Language Understandingtichu提出的BERT 清华 ...
- koa2+mysql+vue实现用户注册、登录、token验证
说明: node.js提供接口,vue展现页面,前后端分离,出于编辑器功能和编辑习惯,vue用HbuilderX,node.js用VScode.(PS:仅作为学习笔记,如有不当之处欢迎指出,在此先谢为 ...
- Linux性能优化实战学习笔记:第七讲
一.进程的状态 1.命令查看 top PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 28961 root 20 0 43816 3148 ...
- Harbor 忘记密码
Harbor密码重置 01,登入到harbor容器里面的数据库上 docker exec -it harbor-db /bin/bash 02,登入数据库 psql -h postgresql -d ...
- Computer-Hunters——测试总结
描述项目的测试工作安排 主要由每个组员在模块功能完成后对自己负责的模块进行测试. 测试工具选择和运用 前端:console界面 后端:人工测试 前端与后端交互:人工测试 测试用例文档pdf的githu ...
- 初探Java设计模式4:一文带你掌握JDK中的设计模式
转自https://javadoop.com/post/design-pattern 行为型模式 策略模式 观察者模式 责任链模式 模板方法模式 状态模式 行为型模式总结 本系列文章将整理到我在Git ...
- vue 学习注意事项
一:插值方式: 1:数据绑定,最常见的形式就是使用 “Mustache” 语法(双大括号)的文本插值 <span>Message: {{ msg }}</span> 通过使用 ...
- [最新].NET Core ORM 开源项目一览,持续更新
截至2019-05-08共收集27个 .NET Core ORM 开源项目,38个 .NET ORM 开源项目. .NET Core ORM 开源项目收集地址:https://github.com/o ...
- Unity Shader 序列帧动画
shader中的序列帧动画属于纹理动画中的一种,主要原理是将给定的纹理进行等分,再根据时间的变化循环播放等分中的一部分. Unity Shader 内置时间变量 名称 类型 描述 _Time floa ...