django模型的继承

很多时候,我们都不是从‘一穷二白’开始编写模型的,有时候可以从第三方库中继承,有时候可以从以前的代码中继承,甚至现写一个模型用于被其它模型继承。这样做的好处,我就不赘述了,每个学习Django的人都非常清楚。

类同于Python的类继承,Django也有完善的继承机制。

Django中所有的模型都必须继承django.db.models.Model模型,不管是直接继承也好,还是间接继承也罢。

你唯一需要决定的是,父模型是否是一个独立自主的,同样在数据库中创建数据表的模型,还是一个只用来保存子模型共有内容,并不实际创建数据表的抽象模型。

Django有三种继承的方式:

  • 抽象基类:被用来继承的模型被称为Abstract base classes,将子类共同的数据抽离出来,供子类继承重用,它不会创建实际的数据表;
  • 多表继承:Multi-table inheritance,每一个模型都有自己的数据库表;
  • 代理模型:如果你只想修改模型的Python层面的行为,并不想改动模型的字段,可以使用代理模型。

注意!同Python的继承一样,Django也是可以同时继承两个以上父类的!

一、 抽象基类:

只需要在模型的Meta类里添加abstract=True元数据项,就可以将一个模型转换为抽象基类。Django不会为这种类创建实际的数据库表,它们也没有管理器,不能被实例化也无法直接保存,它们就是用来被继承的。抽象基类完全就是用来保存子模型们共有的内容部分,达到重用的目的。当它们被继承时,它们的字段会全部复制到子模型中。看下面的例子:

from django.db import modelsclass CommonInfo(models.Model): name = models.CharField(max_length=100) age = models.PositiveIntegerField() class Meta: abstract = True class Student(CommonInfo): home_group = models.CharField(max_length=5) 

Student模型将拥有name,age,home_group三个字段,并且CommonInfo模型不能当做一个正常的模型使用。

抽象基类的Meta数据:

如果子类没有声明自己的Meta类,那么它将继承抽象基类的Meta类。下面的例子则扩展了基类的Meta:

from django.db import modelsclass CommonInfo(models.Model): # ... class Meta: abstract = True ordering = ['name'] class Student(CommonInfo): # ... class Meta(CommonInfo.Meta): db_table = 'student_info' 

这里有几点要特别说明:

  • 抽象基类中有的元数据,子模型没有的话,直接继承;
  • 抽象基类中有的元数据,子模型也有的话,直接覆盖;
  • 子模型可以额外添加元数据;
  • 抽象基类中的abstract=True这个元数据不会被继承。也就是说如果想让一个抽象基类的子模型,同样成为一个抽象基类,那你必须显式的在该子模型的Meta中同样声明一个abstract = True
  • 有一些元数据对抽象基类无效,比如db_table,首先是抽象基类本身不会创建数据表,其次它的所有子类也不会按照这个元数据来设置表名。

如果在你的抽象基类中存在ForeignKey或者ManyToManyField字段,并且使用了related_name或者related_query_name参数,那么一定要小心了。因为按照默认规则,每一个子类都将拥有同样的字段,这显然会导致错误。为了解决这个问题,当你在抽象基类中使用related_name或者related_query_name参数时,它们两者的值中应该包含%(app_label)s%(class)s部分:

  • %(class)s用字段所属子类的小写名替换
  • %(app_label)s用子类所属app的小写名替换

例如,对于common/models.py模块:

from django.db import modelsclass Base(models.Model): m2m = models.ManyToManyField( OtherModel, related_name="%(app_label)s_%(class)s_related", related_query_name="%(app_label)s_%(class)ss", ) class Meta: abstract = True class ChildA(Base): pass class ChildB(Base): pass 

对于另外一个应用中的rare/models.py:

from common.models import Baseclass ChildB(Base): pass 

对于上面的继承关系:

  • common.ChildA.m2m字段的reverse name(反向关系名)应该是common_childa_relatedreverse query name(反向查询名)应该是common_childas
  • common.ChildB.m2m字段的反向关系名应该是common_childb_related;反向查询名应该是common_childbs
  • rare.ChildB.m2m字段的反向关系名应该是rare_childb_related;反向查询名应该是rare_childbs

当然,如果你不设置related_name或者related_query_name参数,这些问题就不存在了。


二、 多表继承

这种继承方式下,父类和子类都是独立自主、功能完整、可正常使用的模型,都有自己的数据库表,内部隐含了一个一对一的关系。例如:

from django.db import modelsclass Place(models.Model): name = models.CharField(max_length=50) address = models.CharField(max_length=80) class Restaurant(Place): serves_hot_dogs = models.BooleanField(default=False) serves_pizza = models.BooleanField(default=False) 

Restaurant将包含Place的所有字段,并且各有各的数据库表和字段,比如:

>>> Place.objects.filter(name="Bob's Cafe")
>>> Restaurant.objects.filter(name="Bob's Cafe")

如果一个Place对象同时也是一个Restaurant对象,你可以使用小写的子类名,在父类中访问它,例如:

>>> p = Place.objects.get(id=12)
# 如果p也是一个Restaurant对象,那么下面的调用可以获得该Restaurant对象。
>>> p.restaurant
<Restaurant: ...>

但是,如果这个Place是个纯粹的Place对象,并不是一个Restaurant对象,那么上面的调用方式会弹出Restaurant.DoesNotExist异常。

让我们看一组更具体的展示,注意里面的注释内容。

>>> from app1.models import Place, Restaurant # 导入两个模型到shell里 >>> p1 = Place.objects.create(name='coff',address='address1') >>> p1 # p1是个纯Place对象 <Place: Place object> >>> p1.restaurant # p1没有餐馆属性 Traceback (most recent call last): File "<console>", line 1, in <module> File "C:\Python36\lib\site-packages\django\db\models\fields\related_descriptors.py", line 407, in __get__ self.related.get_accessor_name() django.db.models.fields.related_descriptors.RelatedObjectDoesNotExist: Place has no restaurant. >>> r1 = Restaurant.objects.create(serves_hot_dogs=True,serves_pizza=False) >>> r1 # r1在创建的时候,只赋予了2个字段的值 <Restaurant: Restaurant object> >>> r1.place # 不能这么调用 Traceback (most recent call last): File "<console>", line 1, in <module> AttributeError: 'Restaurant' object has no attribute 'place' >>> r2 = Restaurant.objects.create(serves_hot_dogs=True,serves_pizza=False, name='pizza', address='address2') >>> r2 # r2在创建时,提供了包括Place的字段在内的4个字段 <Restaurant: Restaurant object> >>> r2.place # 可以看出这么调用都是非法的,异想天开的 Traceback (most recent call last): File "<console>", line 1, in <module> AttributeError: 'Restaurant' object has no attribute 'place' >>> p2 = Place.objects.get(name='pizza') # 通过name,我们获取到了一个Place对象 >>> p2.restaurant # 这个P2其实就是前面的r2 <Restaurant: Restaurant object> >>> p2.restaurant.address 'address2' >>> 

转载于:https://www.cnblogs.com/navysummer/p/10200167.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/387664.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot部署项目到Docker仓库

SpringBoot部署项目到Docker仓库1.开启远程控制端口Centos7开启方式&#xff1a; vim /lib/systemd/system/docker.service找到ExecStart行 ExecStart/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock 重启docker 启动 systemctl start docker守护进程…

人脸识别经典方法

这篇文章是撸主要介绍人脸识别经典方法的第一篇&#xff0c;后续会有其他方法更新。特征脸方法基本是将人脸识别推向真正可用的第一种方法&#xff0c;了解一下还是很有必要的。特征脸用到的理论基础PCA在另一篇博客里&#xff1a;特征脸(Eigenface)理论基础-PCA(主成分分析法)…

Jquery常用正则验证

常用校验的正则表达式var rulesConfig { /** * str.replace(/^\s|\s$/g, ) 解析&#xff1a; str&#xff1a;要替换的字符串 \s : 表示 space &#xff0c;空格 &#xff1a; 一个或多个 ^&#xff1a; 开始&#xff0c;^\s&#xff0c;以空格开始 $&#xff1a; 结束&#x…

svm参数说明

svm参数说明---------------------- 如果你要输出类的概率&#xff0c;一定要有-b参数 svm-train training_set_file model_file svm-predict test_file model_fileoutput_file 自动脚本&#xff1a;Python easy.py train_data test_data 自动选择最优参数&#xff0c;自动进行…

poj-3667(线段树区间合并)

题目链接&#xff1a;传送门 参考文章&#xff1a;传送门 思路&#xff1a;线段树区间合并问题&#xff0c;每次查询到满足线段树的区间最左值&#xff0c;然后更新线段树。 #include<iostream> #include<cstdio> #include<cstring> using namespace std; co…

面试题编程题11-python 生成随机数

随机整数&#xff1a; random.randint(a,b), [a,b] random.randrange(a,b,step) [a,b) 随机实数 random.random()返回0 到1 之间的浮点数转载于:https://www.cnblogs.com/feihujiushiwo/p/10922454.html

车牌识别之颜色选取

车牌定位是车牌识别中第一步&#xff0c;也是最重要的一步。 由于中国车牌种类多样&#xff0c;颜色不一&#xff0c; 再加上车牌经常有污损&#xff0c;以及车牌周围干扰因素太多&#xff0c;都成为了车牌定位的难点。 这里首先使用最简单算法来描述车牌定位&#xff0c;以及他…

Python - 排序( 插入, 冒泡, 快速, 二分 )

插入排序 算法分析 两次循环, 大循环对队列中的每一个元素拿出来作为小循环的裁定对象 小循环对堆当前循环对象在有序队列中寻找插入的位置 性能参数 空间复杂度  O(1) 时间复杂度  O(n^2) 详细代码解读 import randomdef func(l):# 外层循环: 对应遍历所有的无序数据for i…

[EmguCV|C#]使用CvInvoke自己繪製色彩直方圖-直方圖(Hitsogram)系列(4)

2014-02-0610325 0C# 檢舉文章 過年結束了&#xff0c;雖然還是學生所以其實還有兩個禮拜的假期&#xff0c;不過為了不讓自己發慌&#xff0c;趁著假期多利用充實自己&#xff0c;所以提早回到開工狀態&#xff0c;而這次總算要把一直說的自己動手繪製猜色直方圖文章寫出。 …

G.点我

链接&#xff1a;https://ac.nowcoder.com/acm/contest/903/G 题意&#xff1a; X腿与队友到河北省来参加2019河北省大学生程序设计竞赛&#xff0c;然而这场比赛的题目难度实在是太高了。比赛开始一个小时后&#xff0c;X腿仍然没有做出一个题。这时候&#xff0c;X腿惊讶的发…

轮廓的查找、表达、绘制、特性及匹配(How to Use Contour? Find, Component, Construct, Features Match)

前言 轮廓是构成任何一个形状的边界或外形线。前面讲了如何根据色彩及色彩的分布&#xff08;直方图对比和模板匹配&#xff09;来进行匹配&#xff0c;现在我们来看看如何利用物体的轮廓。包括以下内容&#xff1a;轮廓的查找、表达方式、组织方式、绘制、特性、匹配。 查…

Android:IntentService的学习

在Android的四大组件中&#xff0c;Service排行老二&#xff0c;在Android中的主要作用是后台服务&#xff0c;进行与界面无关的操作。由于Service运行在主线程&#xff0c;所以进行异步操作需要在子线进行。为此Android为我们提供了IntentService。 IntentService是一个抽象类…

智能商业大会构造信息化交流平台

在快速发展的当今社会&#xff0c;所有事物都在日新月异地变化着&#xff0c;相较于过去的传统商业的变化速度&#xff0c;现今基于数据的互联网商业变化速度高出了一个量级&#xff0c;同时市场对于企业的应对速度也有了更高的要求&#xff0c;然而面对大体量的数据&#xff0…

itcast-ssh-crm实践

分析 BaseDao 文件上传 转载于:https://www.cnblogs.com/hellowq/p/10209761.html

分类器大牛们

David Lowe&#xff1a;Sift算法的发明者&#xff0c;天才。 Rob Hess&#xff1a;sift的源码OpenSift的作者&#xff0c;个人主页上有openSift的下载链接&#xff0c;Opencv中sift的实现&#xff0c;也是参考这个。 Koen van de Sande&#xff1a;作者给出了sift,densesift,co…

go 成长路上的坑(1)

一、先来看一段代码 package mainimport "fmt"type X struct{}func (x *X) test(){println("h1",x) } func main(){a : X{} a.test()(&X{}).test()(X{}).test() } 猜猜他的结果 二、揭晓答案 package mainimport "fmt"type X struct{}func (…

利用python脚本程序监控文件被修改

需求&#xff1a;利用python编写监控程序&#xff0c;监控一个文件目录&#xff0c;当目录下的文件发生改变时&#xff0c;实现有修改就发报警邮件 邮件使用QQ邮箱&#xff0c;需要开启smtp&#xff0c;使用手机发生短信&#xff0c;腾讯会给你发邮箱密码。如下所示&#xff1a…

Oracle RAC

环境如下&#xff1a; Linux操作系统&#xff1a;Centos 6.5 64bit &#xff08;这个版本的redhat 6内核等OS在安装grid最后执行root.sh时会出现crs-4124&#xff0c;是oracle11.2.0.1的bug&#xff09; VMware version&#xff1a;Workstation 8.0.3 build-703057 Oracle…

好程序员web前端分享MVVM框架Vue实现原理

好程序员web前端分享MVVM框架Vue实现原理&#xff0c;Vue.js是当下很火的一个JavaScript MVVM库&#xff0c;它是以数据驱动和组件化的思想构建的。相比于Angular.js和react.js更加简洁、更易于理解的API&#xff0c;使得我们能够快速地上手并使用Vue.js。​1.什么是MVVM呢&…

HDU - 3516 Tree Construction

HDU - 3516 思路&#xff1a; 平行四边形不等式优化dp &#xff1a;&#xff09; 代码&#xff1a; #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(4) #include<bits/stdc.h> using namespace std; #define y1 y11 #define fi first #define se…