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 ...
随机推荐
- 不使用已下载的package pip 安装 & 出现time out error
pip install XX + --no-cache-dir 安装出现time out error时: pip --default-timeout=10000 install XX
- zz深度学习中的注意力模型
中间表示: C -> C1.C2.C3 i:target -> IT j: source -> JS sim(Query, Key) -> Value Key:h_j,类似某种 ...
- linux pkgsrc 学习(一) 安装pkgsrc
使用pkgsrc.joyent.com 提供的linux 包 下载包 # # Copy and paste the lines below to install the 64-bit EL 7.x s ...
- fft.ntt,生成函数,各种数和各种反演
前置知识: 一,导数 倒数其实就是函数的斜率函数 设D[f(x)]表示f(x)的导数,则满足 $$1,D[f(x)]=\lim\limits_{\delta x->\infty}\frac{f( ...
- 关于对pei
我现在才开始整理这个不算晚吧...... 望轻喷 学习博客 我们需要四个程序 1.暴力 2.“正解” 3.数据生成器 4.检查程序 暴力: 就是暴力 eg: #include <cstdio&g ...
- 在.Net Core中使用HttpClient添加证书
最近公司要对接电信物联网北向API接口,当调用Auth授权接口时,需要用到证书,此篇文章记录下遇到的坑~ 有两种调用接口的方式,下面是两种方式的简单示例 1.使用HttpClient public s ...
- java十题
这是我收集的10个最棘手的Java面试问题列表.这些问题主要来自 Java 核心部分 ,不涉及 Java EE 相关问题.你可能知道这些棘手的 Java 问题的答案,或者觉得这些不足以挑战你的 Jav ...
- html5手机web页面底部菜单
一.效果图 二.HTML代码 <header class="text-center">TOP</header> <div id="conte ...
- CSS3做动物走路效果
CSS3做动物走路效果 采用的CSS3切换序列帧做 核心代码如下<pre>.game .role { width: 60px; height: 86px; position: absolu ...
- Postman界面了解
Postman界面了解 2019年3月21日去面试了一家软件测试,本以为自己对简历上写的技能都熟悉,跳个槽,涨点工资,想象很美好,现实太残忍.当问到做接口测试postman和swagger工具的时候, ...