【Django 018】Django2.2数据模型models的继承以及abstract的使用

python做为一门面向对象语音,其继承特性是做的非常好的。如果能在models定义中将一些通用字段放在父类中,子类直接继承,然后添加一些自己独有的字段,岂不是可以省很多创建模型的时间。这一篇我们就来看看这个问题。

我是T型人小付,一位坚持终身学习的互联网从业者。喜欢我的博客欢迎在csdn上关注我,如果有问题欢迎在底下的评论区交流,谢谢。

纯语法定义继承

models.py中创建如下People类做为一会要用的父类

class People(models.Model):
    p_name = models.CharField(max_length=16)
    p_sex = models.BooleanField(default=True)

然后创建两个子类AmericanChinese继承自People

class American(People):
    a_state = models.CharField(max_length=16)


class Chinese(People):
    c_province = models.CharField(max_length=16)

按照正常逻辑,我们只想要AmericanChinese这两张表,但是完成makemigrationsmigrate以后和我们设想的不一样,一共出现了三张表,也就是说People表也被创建了。

而且在AmericanChinese中都多了一个叫people_ptr_id的字段,查看DDL如下

create table Four_american
(
    people_ptr_id int         not null
        primary key,
    a_state       varchar(16) not null,
    constraint Four_american_people_ptr_id_733979de_fk_Four_people_id
        foreign key (people_ptr_id) references Four_people (id)
);
create table Four_chinese
(
    people_ptr_id int         not null
        primary key,
    c_province    varchar(16) not null,
    constraint Four_chinese_people_ptr_id_15a467cd_fk_Four_people_id
        foreign key (people_ptr_id) references Four_people (id)
);

发现这个people_ptr_id既是每个表的主键,又是指向父类表主键的一个外键。按照前面的学习,这是一对一的SQL逻辑。下面我们就往两个子类的表中添加数据来验证一下。

创建如下的路由和view函数来添加数据

path('add_american/', views.add_american, name='add_american'),
path('add_chinese/', views.add_chinese, name='add_chinese'),
def add_american(request):
    state = request.GET.get('state')
    name = request.GET.get('name')
    american = American()
    american.p_name = name
    american.a_state = state
    american.save()
    return HttpResponse('Add american successfully')


def add_chinese(request):
    province = request.GET.get('province')
    name = request.GET.get('name')
    chinese = Chinese()
    chinese.p_name = name
    chinese.c_province = province
    chinese.save()
    return HttpResponse('Add chinese successfully')

然后就可以通过类似http://127.0.0.1:8000/four/add_chinese/?province=hubei&name=hanmeimeihttp://127.0.0.1:8000/four/add_american/?state=californiai&name=james来添加数据了。结果生成的数据如下

American:
1-american.png

Chinese:
2-chinese.png

People:
3-people.png

添加的数据在添加到American或者Chinese的同时也会被添加到People中,并且通过id或者people_ptr_id来唯一确定。

这显然不是我们想要的现象,理想的情况是子类只继承父类的字段,而每个子类是彼此独立的

直接执行python manage.py migrate Four 0003_auto_20200401_2321撤销这一次的迁移

关于迁移的原理和撤销回退操作可以参考我的另一篇博客《Django2.2中迁移(makemigrations和migrate)的原理和撤销回退操作图文详解》

加上Abstract定义继承

撤销了上面的迁移以后,我们修改下models.py中的People的定义

class People(models.Model):
    p_name = models.CharField(max_length=16)
    p_sex = models.BooleanField(default=True)

    class Meta:
        abstract = True

这里在Meta中添加了abstract=True的说明,将People变为一个抽象类,也就意味着不会在数据库中显示了。

然后再进行迁移,之后发现数据库中只有子类的两个表了
4-abstract.png

点开两个表看一下,发现成功继承了Peoplep_namep_sex字段

American:
5-new-american.png

Chinese:
6-new-chinese.png

这表结构和我们之前设想的一样,DDL也证明没有和别的表关联

create table Four_chinese
(
    id         int auto_increment
        primary key,
    p_name     varchar(16) not null,
    p_sex      tinyint(1)  not null,
    c_province varchar(16) not null
);
create table Four_american
(
    id      int auto_increment
        primary key,
    p_name  varchar(16) not null,
    p_sex   tinyint(1)  not null,
    a_state varchar(16) not null
);

下面来添加数据验证下,同样使用上面的路由和view函数,通过类似http://127.0.0.1:8000/four/add_american/?state=maryland&name=jameshttp://127.0.0.1:8000/four/add_chinese/?province=taiwan&name=amei来添加数据。

发现两个表的数据是完全独立的,id彼此没有顺序

American:
7-american.png

Chinese:
8-chinese.png

这样就达到了只继承字段,不添加额外表关联的目的。

总结

企业开发中,合理利用继承可以使得模型的创建更高效。不过还有另一种情况,就是和你合作的那个数据开发不会写python所以只能写好SQL,给了你一堆现成的表,又该如何反向转为Django中的模型供我们使用呢?我们下一篇一起来看看这个问题。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值