Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Django treebeard MP节点预取子体_Django_Django Rest Framework_Django Treebeard - Fatal编程技术网

Django treebeard MP节点预取子体

Django treebeard MP节点预取子体,django,django-rest-framework,django-treebeard,Django,Django Rest Framework,Django Treebeard,我正在使用django树beard在django rest框架中开发一个具有分层数据结构的应用程序。我的(简化的)主模型如下所示 class Task(MP_Node): name = models.CharField(_('name'), max_length=64) started = models.BooleanField(default=True) 我目前试图实现的是一个所有根节点的列表视图,其中显示额外的字段(例如是否所有子节点都已启动)。为此,我指定了一个视图: c

我正在使用
django树beard
django rest框架
中开发一个具有分层数据结构的应用程序。我的(简化的)主模型如下所示

class Task(MP_Node):
    name = models.CharField(_('name'), max_length=64)
    started = models.BooleanField(default=True)
我目前试图实现的是一个所有根节点的列表视图,其中显示额外的字段(例如是否所有子节点都已启动)。为此,我指定了一个视图:

class TaskViewSet(viewsets.ViewSet):

    def retrieve(self, request, pk=None):
        queryset = Task.get_tree().filter(depth=1, job__isnull=True)
        operation = get_object_or_404(queryset, pk=pk)
        serializer = TaskSerializer(operation)
        return Response(serializer.data)
和序列化程序

class TaskSerializer(serializers.ModelSerializer):
    are_children_started = serializers.SerializerMethodField()

    def get_are_children_started(self, obj):
        return all(task.started for task in Task.get_tree(obj))
这一切都有效,我得到了预期的结果。然而,我遇到了一个N+1查询问题,对于每个根任务,我需要分别获取所有子任务。通常,这可以通过使用
prefetch\u related
来解决,但由于我使用了
django树beard
中的物化路径结构,任务模型之间没有django关系,因此
prefetch\u related
不知道该怎么做。我曾尝试使用自定义预取对象,但由于这仍然需要Django关系路径,因此无法使其工作

我目前的想法是使用指向其根节点的外键扩展任务模型,如下所示:

root_node = models.ForeignKey('self', null=True,
                              related_name='descendant_tasks',
                              verbose_name=_('root task')
                              )
root_node = models.ForeignKey('self', null=True,
                          related_name='descendant_tasks',
                          verbose_name=_('root task')
                          )

为了使MP关系显式,以便可以查询它。然而,这确实有点像是一种非干性的方法,所以我想知道是否有人对如何处理它有其他建议。

最后,我确实为每个任务添加了一个外键,指向其根节点,如下所示:

root_node = models.ForeignKey('self', null=True,
                              related_name='descendant_tasks',
                              verbose_name=_('root task')
                              )
root_node = models.ForeignKey('self', null=True,
                          related_name='descendant_tasks',
                          verbose_name=_('root task')
                          )
我更新了任务模型上的save方法,以确保始终指向正确的根节点

def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
    try:
        self.root_task = self.get_root()
    except ObjectDoesNotExist:
        self.root_task = None

    return super(Task, self).save(force_insert=False, force_update=False, using=None,
                                  update_fields=None
                                  )
这使我可以使用
prefetch\u related('substands')
简单地预取所有子体

每当需要嵌套子体时,我都会使用以下函数再次嵌套展开的子体列表

def build_nested(tasks):

    def get_basepath(path, depth):
        return path[0:depth * Task.steplen]

    container, link = [], {}
    for task in sorted(tasks, key=attrgetter('depth')):
        depth = int(len(task.path) / Task.steplen)
        try:
            parent_path = get_basepath(task.path, depth - 1)
            parent_obj = link[parent_path]
            if not hasattr(parent_obj, 'sub_tasks'):
                parent_obj.sub_tasks = []
            parent_obj.sub_tasks.append(task)
        except KeyError:  # Append it as root task if no parent exists
            container.append(task)

        link[task.path] = task

    return container