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直接放在特定继承层次结构中的父类中.
如果您无法修改父模型,则此解决方案将不起作用.在这种情况下,您几乎无法手动检查所有子类.
Ale*_*lli 21
在Python中,赋予了("新式")类X,你可以得到它(直接)与子类X.__subclasses__()
,它返回类对象的列表.(如果你想要"进一步的后代",你还需要调用__subclasses__
每个直接子类等等 - 如果你需要有关如何在Python中有效地做到这一点的帮助,请问!).
一旦你以某种方式确定了一个感兴趣的子类(也许所有这些,如果你想要所有子类的实例等),getattr(parentclass,'%s_set' % childclass.__name__)
应该有所帮助(如果是子类的名字'foo'
,这就像访问一样parentclass.foo_set
- 不多也不少).同样,如果您需要澄清或示例,请询问!
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进化时它不能保证稳定,但它可以实现这一点,并且可以在需要时即时使用.
您可以使用django-polymorphic为此。
它允许自动将派生类转换回它们的实际类型。它还提供 Django 管理支持、更高效的 SQL 查询处理以及代理模型、内联和表单集支持。
基本原则似乎被重新发明了很多次(包括 Wagtail 的.specific
,或本文中概述的示例)。然而,需要付出更多努力,以确保它不会导致 N 查询问题,或者与管理员、表单集/内联或第三方应用程序很好地集成。