在不知道子类名称的情况下,如何访问 django 中对象的子类?
- 2025-02-21 08:48:00
- admin 原创
- 18
问题描述:
在 Django 中,当您有一个父类和多个从该类继承的子类时,您通常会通过 parentclass.childclass1_set 或 parentclass.childclass2_set 访问子类,但是如果我不知道我想要的特定子类的名称怎么办?
有没有办法在不知道子类名的情况下获取父->子方向的相关对象?
解决方案 1:
(更新:对于 Django 1.2 及更新版本,可以跨反向 OneToOneField 关系(从而沿着继承层次结构向下)跟踪 select_related 查询,有一种更好的技术可用,它不需要real_type
在父模型上添加字段。它在django-model-utils项目中作为InheritanceManager提供。)
执行此操作的常用方法是将 ForeignKey 添加到 Parent 模型上的 ContentType,该模型存储了正确的“叶”类的内容类型。如果没有这个,您可能必须在子表上执行大量查询才能找到实例,具体取决于继承树的大小。以下是我在一个项目中执行此操作的方法:
from django.contrib.contenttypes.models import ContentType
from django.db import models
class InheritanceCastModel(models.Model):
"""
An abstract base class that provides a ``real_type`` FK to ContentType.
For use in trees of inherited models, to be able to downcast
parent instances to their child types.
"""
real_type = models.ForeignKey(ContentType, editable=False)
def save(self, *args, **kwargs):
if self._state.adding:
self.real_type = self._get_real_type()
super(InheritanceCastModel, self).save(*args, **kwargs)
def _get_real_type(self):
return ContentType.objects.get_for_model(type(self))
def cast(self):
return self.real_type.get_object_for_this_type(pk=self.pk)
class Meta:
abstract = True
它被实现为一个抽象基类以使其可重用;您也可以将这些方法和 FK 直接放到特定继承层次结构中的父类上。
如果您无法修改父模型,则此解决方案将不起作用。在这种情况下,您几乎只能手动检查所有子类。
解决方案 2:
在 Python 中,给定一个(“新式”)类 X,您可以使用 获取其(直接)子类X.__subclasses__()
,这将返回类对象列表。(如果您想要“进一步的后代”,您还必须调用__subclasses__
每个直接子类,等等——如果您需要有关如何在 Python 中有效地执行此操作的帮助,请询问!)。
一旦您以某种方式确定了感兴趣的子类(如果您想要所有子类的实例,则可能是所有子类),getattr(parentclass,'%s_set' % childclass.__name__)
应该会有所帮助(如果子类的名称是'foo'
,这就像访问一样parentclass.foo_set
——不多也不少)。再次强调,如果您需要说明或示例,请询问!
解决方案 3:
Carl 的解决方案很好,如果有多个相关的子类,可以手动执行此操作:
def get_children(self):
rel_objs = self._meta.get_all_related_objects()
return [getattr(self, x.get_accessor_name()) for x in rel_objs if x.model != type(self)]
它使用了 _meta 之外的函数,虽然不能保证随着 django 的发展而保持稳定,但是它可以起到作用,并且可以在需要时即时使用。
解决方案 4:
事实证明我真正需要的是这个:
使用内容类型和继承感知管理器对继承进行建模
这对我来说非常有效。不过,也感谢其他人。光是阅读你们的回答我就学到了很多东西!
解决方案 5:
您可以为此使用django-polymorphic 。
它允许自动将派生类转换回其实际类型。它还提供 Django 管理支持、更高效的 SQL 查询处理以及代理模型、内联和表单集支持。
基本原理似乎被重新发明了很多次(包括 Wagtail 的.specific
,或本文中概述的示例)。然而,需要付出更多努力才能确保它不会导致 N 查询问题,或者与管理员、表单集/内联或第三方应用程序很好地集成。
解决方案 6:
这是我的解决方案,再次使用它,_meta
所以不能保证其稳定性。
class Animal(models.model):
name = models.CharField()
number_legs = models.IntegerField()
...
def get_child_animal(self):
child_animal = None
for r in self._meta.get_all_related_objects():
if r.field.name == 'animal_ptr':
child_animal = getattr(self, r.get_accessor_name())
if not child_animal:
raise Exception("No subclass, you shouldn't create Animals directly")
return child_animal
class Dog(Animal):
...
for a in Animal.objects.all():
a.get_child_animal() # returns the dog (or whatever) instance
解决方案 7:
您可以通过查找父类中所有属于 django.db.models.fields.related.RelatedManager 实例的字段来实现此目的。从您的示例来看,您谈论的子类似乎不是子类。对吗?
- 2025年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)