Django5框架之代理模型

文章介绍了在Django中如何使用代理模型来修改模型的行为,如添加方法或改变默认管理器,同时保持数据存储在同一张表上。通过实例演示了如何创建代理模型,以及其在继承关系和管理器定制上的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在Django模型中使用多表继承时,每个子类模型都会创建一张新表,这是因为子类需要一个地方存储基类中不存在的数据字段。但是,有时候如果只想修改模型的Python级行为(例如修改默认管理器或添加一个方法),这时就需要使用代理模型了。

使用代理模型继承的目标就是为原模型创建一个“代理”。在设计时可以创建、删除或更新代理模型的实例,全部数据都会存储成与使用原模型(未代理)一样的形式。这里稍微有些不同的是,在设计时可以修改代理默认的模型排序和管理器,而不需要修改原模型。

使用代理模型时就像使用普通模型一样进行声明,只需要告诉Django框架这是一个代理模型,通过将Meta类的proxy属性设置为True即可。

例如,如果打算为一个Person模型添加一个方法,可以参照下面的代码示例。

【代码3-25】

01  from django.db import models
02  
03  class Person(models.Model):
04      first_name = models.CharField(max_length=30)
05      last_name = models.CharField(max_length=30)
06  
07  class Child(Person):
08      class Meta:
09          proxy = True
10  
11      def do_something(self):
12          # ...
13          pass
14    #...
15    pass

【代码分析】

在第03~05行代码中,定义了一个Person类,它是一个用于描述人的模型。其中,在第04、05行代码中定义了两个属性,即first_name和last_name。

在第07~15行代码中,定义了一个Child类,它继承自父类Person,是一个用于描述孩子的模型。具体内容说明如下:

  • 在第08、09行代码中,通过Meta类定义了“proxy=True”属性,表明该类是一个代理类。
  • 在第11~13行代码中,为Person模型添加了一个方法do_something。

根据上面的代码,子类Child与父类Person操作同一张数据表。另外,Person模型的实例能通过Child模型访问,反之亦然。

>>> p = Person.objects.create(first_name="king")

>>> Child.objects.get(first_name="king")

<Child: king>

使用代理模型还可以定义模型的另一种默认排序方法。比如在【代码3-25】中,也许不期望总是对Person进行排序,但在使用代理时总是会依据last_name属性进行排序,解决方法可参看下面的代码示例。

【代码3-26】

01  class OrderedPerson(Person):
02      class Meta:
03          ordering = ["last_name"]
04          proxy = True
05      #...
06      pass

【代码分析】

通过上面的定义,普通Person模型的查询结果就不会被排序了。而通过第03行代码的定义,OrderedPerson模型的查询结果会按照last_name属性排序。

再次回看一下【代码3-24】,当使用Person模型对象进行查询时,Django框架是不会返回Child模型对象的,对于Person模型对象的查询结果集,总是返回相对应的类型(QuerySet仍会返回请求的模型)。

代理对象存在的意义是帮设计人员复用原Person模型所提供的代码,以及自定义的功能代码(并未依赖其他代码)。对于代理模型,是不存在任何方法来保证在设计时创建完代理后,能够替换所有Person(或其他)模型。

在使用代理模型时,对于其继承的基类是有约束条件的。一个代理模型必须继承一个非抽象模型类,而不能继承多个非抽象模型类的。原因在于,代理模型无法在不同数据表之间提供任何行间连接。一个代理模型既可以继承任意数量的抽象模型类(假设它没有定义任何模型字段),也可以继承任意数量的代理模型(只需共享同一个非抽象父类)。

另外,如果未在代理模型中指定模型管理器,则默认会从父类模型中继承。而如果在代理模型中指定了管理器,则该管理器就会成为默认的管理器,同时父类中所定义的管理器也仍可使用。

基于【代码3-25】和【代码3-26】的示例,我们可以在查询Person模型时修改默认管理器,示例代码如下:

【代码3-27】

01  from django.db import models
02  
03  class NewManager(models.Manager):
04      # ...
05      pass
06  
07  class Child(Person):
08      objects = NewManager()
09  
10      class Meta:
11          proxy = True
12      #...
13      pass

【代码分析】

在第03~05行代码中,在不替换已存在的默认管理器情况下,为代理模型添加了新管理器NewManager。

另外,官方文档中对“自定义管理器”介绍了一种技巧,即先创建一个包含新管理器的基类,然后在继承列表中的主类后追加这个新管理器的基类。不过,通常情况下可能是不需要这么做的。

本文节选自《Django 5企业级Web应用开发实战(视频教学版)》,获出版社和作者授权发布。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值