如何在不知道子类名称的情况下访问django中对象的子类?

Gab*_*ley 78 python django many-to-many

在Django中,当你有一个父类和多个从它继承的子类时,你通常会通过parentclass.childclass1_set或parentclass.childclass2_set访问一个子节点,但如果我不知道我想要的特定子类的名称呢?

有没有办法在不知道子类名的情况下获取parent-> child方向的相关对象?

Car*_*yer 81

(更新:对于Django 1.2及更新版本,它可以跟踪反向OneToOneField关系中的select_related查询(以及因此向下继承层次结构),有一种更好的技术可用,不需要real_type在父模型上添加字段.它可以作为继承管理器django-model-utils项目.)

通常的方法是在Parent模型上向ContentType添加ForeignKey,它存储正确的"leaf"类的内容类型.如果没有这个,您可能必须对子表执行大量查询才能找到实例,具体取决于继承树的大小.以下是我在一个项目中的表现:

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
Run Code Online (Sandbox Code Playgroud)

这是作为一个抽象基类实现的,以使其可重用; 您还可以将这些方法和FK直接放在特定继承层次结构中的父类中.

如果您无法修改父模型,则此解决方案将不起作用.在这种情况下,您几乎无法手动检查所有子类.

  • @sunprophit您需要更仔细地重新阅读我的回复.是的,当然你可以使用`real_type`字段(在上面的代码中作为`cast()`方法)来执行`self.child_object()`,并且只对一个实例进行一次查询.但是,如果您有一个充满实例的查询集,则会成为N个查询.在单个查询中获取对象的整个查询集的子类数据的唯一方法是使用InheritanceManager所做的连接. (2认同)

Ale*_*lli 21

在Python中,赋予了("新式")类X,你可以得到它(直接)与子类X.__subclasses__(),它返回类对象的列表.(如果你想要"进一步的后代",你还需要调用__subclasses__每个直接子类等等 - 如果你需要有关如何在Python中有效地做到这一点的帮助,请问!).

一旦你以某种方式确定了一个感兴趣的子类(也许所有这些,如果你想要所有子类的实例等),getattr(parentclass,'%s_set' % childclass.__name__)应该有所帮助(如果是子类的名字'foo',这就像访问一样parentclass.foo_set- 不多也不少).同样,如果您需要澄清或示例,请询问!

  • 对不起,当我说"可能_in fact_是SomeChild的一个实例"时,我不清楚.你拥有的对象是在Python家长的一个实例,但它可能在SomeChild表相关表项,这意味着你可能更愿意与它合作的SomeChild实例. (2认同)

Pau*_*lan 5

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)]
Run Code Online (Sandbox Code Playgroud)

它使用了_meta之外的一个函数,当django进化时它不能保证稳定,但它可以实现这一点,并且可以在需要时即时使用.


Gab*_*ley 5

事实证明,我真正需要的是:

具有内容类型和继承感知管理器的模型继承

这对我来说非常有用.不过,感谢其他所有人.我只是阅读你的答案我学到了很多东西!


vdb*_*oor 5

您可以使用django-polymorphic为此。

它允许自动将派生类转换回它们的实际类型。它还提供 Django 管理支持、更高效的 SQL 查询处理以及代理模型、内联和表单集支持。

基本原则似乎被重新发明了很多次(包括 Wagtail 的.specific,或本文中概述的示例)。然而,需要付出更多努力,以确保它不会导致 N 查询问题,或者与管理员、表单集/内联或第三方应用程序很好地集成。