【发布时间】:2021-04-04 08:16:13
【问题描述】:
先决条件
我要实现抽象继承:
class Base(models.Model):
title = models.CharField()
slug = models.SlugField()
description = models.TextField()
class Meta:
abstract = True
class ChildA(Base):
foo = models.CharField()
class ChildB(Base):
bar = models.CharField()
出于多种原因,我需要这些类的层次结构的 db 表示。所以我想创建一个像这样的模型(left 和right 属性允许我们识别实例在节点树中的位置):
class Node(models.Model):
app_label = models.CharField()
model_name = models.CharField()
parent = models.ForeignKey('self', blank=True, null=True)
right = models.PositiveIntegerField()
left = models.PositiveIntegerField()
问题
我需要类似的东西:
class Base(models.Model):
...
def __init_subclass__(cls):
app_label = cls._meta.app_label
model_name = cls._meta.model_name
parent_id = ? # I am not sure how do we get parent's id for now, but it should be manageable
obj = Node.objects.create('app_label'=app_label, 'model_name'=model_name, 'parent'=parent_id)
obj.save()
因此,当我们对抽象模型进行子类化时,会创建一个新节点来表示层次结构树中的这个新模型。不幸的是,它不起作用。似乎__init_subclass__ 在Model 类被正确初始化之前被调用,所以cls._meta.model_name 将返回不正确的值(实际上是父级的model_name)。我们可以绕过这个(或使用其他钩子)吗?
其他问题
我不确定整个想法是否合理。我以前使用多表继承,但在某些时候 SQL 查询变得非常丑陋,所以我试图通过使用抽象模型来解决它。但是我们仍然需要将模型相互联系起来,节点树似乎很有吸引力。这样我就得到了一个同时管理多个表的具体模型,如下所示:
class NodeManager(models.Manager):
def get_queryset(self):
root = self._get_root_node()
fields = root._meta.get_fields()
field_names = [field.name for field in fields]
descendants = list(self._get_descendant_models(root))
queryset_list = []
for model in descendants:
qs = model.objects.values(*field_names)
annotated_qs = qs.annotate(
resource_model=models.Value(
root._meta.model_name,
models.CharField(max_length=120)
)
)
queryset_list.append(annotated_qs)
if len(queryset_list) > 1:
merged_queryset = queryset_list[0].union(*queryset_list[1:])
elif len(queryset_list) == 1:
merged_queryset = queryset_list[0]
else:
merged_queryset = None
return merged_queryset
我猜这不是应该使用管理器的方式,所以我不确定它是否可以。 我不想专注于此,主要是为了更好地了解我的目标。但是,如果您让我知道您是否认为这很好,我将不胜感激。
【问题讨论】:
标签: python django database-design