使用多态节点类型在django中建模分层数据

时间:2013-06-23 05:12:01

标签: django hierarchical-data

我有两个基本模型,一个Command和一个Flow。流可以包含一系列命令或其他嵌套流。因此,任何给定的Flow都可以包含Step或Flow类型的子列表。 (这类似于您可能在文件系统中建模的文件和目录。)

我尝试使用ContentTypes,Generic relations和mptt(不允许通用内容类型AFAIK)对此进行建模,但没有成功。以下是我的基本模型:

class Step(models.Model):
    parent     = models.ForeignKey('Step', null=True)
    name        = models.CharField( max_length=100 )
    start_time  = models.DateTimeField(null=True)
    end_time    = models.DateTimeField(null=True)
    state       = models.CharField( max_length=1, default='u' )

class Flow(Step):
    type  = models.CharField( max_length=1 )

    def getChildren(self):
        # todo: the steps returned here need to be sorted by their order in the flow
        return Step.objects.filter(parent_id=self.parent_id)

    def run(self):
      for child in self.getChildren():
          print("DEBUG: run method processing a {0}".format(child.__class__.__name__) )
          # if this is a flow, run it
          # else if it's a command, execute it

class Command(Step):
    exec_string = models.TextField()

我希望能够在我的应用程序中创建Flow,查询子项,然后根据其类型处理每个子项(执行命令,流程得到递归处理。)

我希望对我的代码进行任何更正,这将使得这可能或甚至评论我正在接近这个问题,这是Django完全错误的方式。

编辑:我应该补充一点,我使用的是Python 3.3和Django dev(命名为1.6)

2 个答案:

答案 0 :(得分:3)

我终于通过IRC的一些很好的帮助找到了答案,并希望分享它以防其他人遇到同样的问题。

我唯一要改变的是Flow.getChildren()。

def getChildren(self):
    # Get a list of all the attrs relating to Child models.
    child_attrs = dict(
        (rel.var_name, rel.get_cache_name())
        for rel in Step._meta.get_all_related_objects()
        if issubclass(rel.field.model, Step) and isinstance(rel.field, models.OneToOneField)
    )

    objs = []
    for obj in self.children.all().select_related(*child_attrs.keys()):
        # Try to find any children...
        for child in child_attrs.values():
            sobj = obj.__dict__.get(child)
            if sobj is not None:
                break
        objs.append(sobj)
    return objs

如果有人有一个更清洁的解决方案,我很乐意看到它,特别是因为这看起来似乎很多工作似乎框架应该更直接地处理。

答案 1 :(得分:0)

跳出来的东西是“返回Step.objects.filter(parent_id = self.parent_id)”。我相信它应该是“返回Step.objects.filter(parent__pk = self.parent.pk)”