如何在不知道子类的名称的情况下访问django中的对象的子类?
在Django中,当你有一个父类和多个从它inheritance的子类时,你通常会通过parentclass.childclass1_set或parentclass.childclass2_set来访问一个子类,但是如果我不知道我想要的特定子类的名字呢?
有没有办法在不知道子类名称的情况下在父 – >子方向获取相关对象?
( 更新 :对于Django 1.2和更新的版本,它可以通过反向OneToOneField关系(从而向下inheritance层次结构)进行real_type
查询,还有更好的方法,不需要在父模型中添加real_type
字段。 django-model-utils项目。)
通常的做法是在Parent模型上添加一个ForeignKey到ContentType,它存储了正确的“leaf”类的内容types。 如果没有这个,你可能需要在子表上进行大量的查询来查找实例,具体取决于inheritance树的大小。 以下是我在一个项目中做到的:
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 not 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直接放到您的特定inheritance层次结构的父类中。
如果您无法修改父级模型,则此解决scheme将无法工作。 在这种情况下,你几乎不能手动检查所有的子类。
在Python中,如果给定一个(“新样式”)类X,则可以使用X.__subclasses__()
获取其(直接)子X.__subclasses__()
,该X.__subclasses__()
将返回一个类对象列表。 (如果你想要“更进一步的后代”,你还必须在每个直接子类等上调用__subclasses__
,如果你需要关于如何在Python中有效地实现这个function的帮助,就问一下!)。
一旦你以某种方式确定了一个感兴趣的子类(也许是所有这些类,如果你想要所有子类的实例等), getattr(parentclass,'%s_set' % childclass.__name__)
应该有帮助(如果子类的名字是'foo'
,这就像访问parentclass.foo_set
– 不多不less)。 再次,如果你需要澄清或例子,请问!
事实certificate,我真正需要的是这样的:
模型inheritance与内容types和inheritance感知pipe理器
这对我来说是完美的。 不过感谢所有人。 我读了很多,只是看你的答案!
卡尔的解决scheme是一个很好的解决scheme,如果有多个相关的子类,这里有一种方法可以手动完成:
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的稳定性,但是它可以在需要时dynamic使用。
这是我的解决scheme,它也使用_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
你可以使用django-polymorphic 。
它允许自动将派生类转换回它们的实际types。 它还提供了Djangopipe理支持,更高效的SQL查询处理以及代理模型,内联和formset支持。
基本原理似乎被多次改造(包括W's的具体,或在这篇文章中概述的例子)。 但是,需要更多的努力来确保它不会导致N-query问题,或者很好地与admin,formset / inline或第三方应用程序集成。
你可以做到这一点,寻找父级的所有字段是django.db.models.fields.related.RelatedManager的一个实例。 从你的例子来看,你所讲的子类不是子类。 对?
使用代理的另一种方法可以在这篇博客文章中find。 像其他解决scheme一样,它有其好处和责任,这些都很好地结束了。