简介
我们目前正在开发一个Django REST框架项目。它连接到一个Postgres数据库,这个数据库保存了一些层次结构(树形结构)的数据,这些数据有很多层深。我们应该为GET请求提供一个端点,当没有提供参数时,它会返回整个嵌套的树形结构(父、子、孙等)。
示例数据
下表显示了区域的样本数据,其中每个区域都可以有一个父代,表示区域的层次结构。在本例中,层次结构有三个层次(世界〉洲〉国家)。但实际上,树可以更深,具有未知数量的层次(世界〉洲〉国家〉省〉城市〉社区〉等等)。
| 标识符|区域|父区域标识|
| - -|- -|- -|
| 一个|全世界|空值|
| 2个|欧洲|一个|
| 三个|亚洲|一个|
| 四个|非洲|一个|
| 五个|比利时|2个|
| 六个|德国|2个|
| 七个|西班牙|2个|
| 八个|日本|三个|
| 九个|印度尼西亚|三个|
| 10个|越南|三个|
| 十一|坦桑尼亚|四个|
| 十二|埃及|四个|
| 十三|塞内加尔的|四个|
我们的目标
下面显示的JSON输出是我们尝试实现的,它是/region资源的GET请求的响应主体的目标。
{
"id":1,
"region":"world",
"children":[
{
"id":2,
"region":"europe",
"children":[
{
"id":5,
"region":"belgium"
},
{
"id":6,
"region":"germany"
},
{
"id":7,
"region":"spain"
}
]
},
{
"id":3,
"region":"asia",
"children":[
{
"id":8,
"region":"japan"
},
{
"id":9,
"region":"indonesia"
},
{
"id":10,
"region":"vietnam"
}
]
},
{
"id":4,
"region":"africa",
"children":[
{
"id":11,
"region":"tanzania"
},
{
"id":12,
"region":"egypt"
},
{
"id":13,
"region":"senegal"
}
]
}
]
}
"我们迄今为止的努力和成就"
下面是我们实现目标的方法。参见下面的代码,了解模型、序列化器和视图:
Models.py
________
class HierarchyData:
region = models.CharField(max_length=100, null=False, default=None)
parent = models.ForeignKey("self", models.DO_NOTHING, null=True, blank=True, db_column='parent', related_name="children")
Serializers.py
__________
class HeirarchyDataSerializer(serialisers.ModelSerializer):
class Meta:
model = HierarchyData
fields = [“id”,”region”, “children”]
Views.py
__________
Class ListHierarchyData(generics.ListAPIView):
queryset = HierarchyData.objects.all()
serializer_class = HeirarchyDataSerializer
permission_classes = [isAuthenticated]
当我调用给定场景的端点时,我得到如下格式的JSON响应:
{
“id”: 1,
“region”: “world”,
“children”: [ 2,3,4]
}
似乎没有回答我的问题的相关堆栈溢出问题
- How to recursively query in django efficiently?
- Django - Models - Recursively retrieve parents of a leaf node
- Django self-recursive foreignkey filter query for all childs
上面提到的问题部分解决了我的问题,但我仍然无法得到想要的结果。请参阅下面的详细信息:
1:我不能直接接触数据库,我只能通过ORM与数据库交互。
2:递归超时,无法序列化,表示“Model”类型的对象不可序列化。
3:这一个对我部分有效:基于这篇文章,我尝试在模型中添加以下内容:
def get_children(self):
children = list()
children.append(self)
for child in self.children.all():
children.extend(children.get_children())
return children
然后我得到所有嵌套的子级,但是所有嵌套的值都在同一层。例如world有子级[2,3,4],而那些子级本身有(grand)子级。然后它在同一行列出这些子级,例如children = [2,3,4,5,6,7,8,9,10,11,12,13]。这并不代表示例数据中的层。
然后,我尝试了以下模型解决方案:
def get_all_children(self, include_self=True):
r = []
if include_self:
r.append(self)
for c in Person.objects.filter(parent=self):
_r = c.get_all_children(include_self=True)
if 0 < len(_r):
r.extend(_r)
return r
这一个工作;它会找到嵌套的子代,但会产生两个问题:a.当我按原样使用代码时,它会给我序列化器错误,但是如果我在序列化器中添加'get_all_children',并为该属性添加一个不同的序列化器,那么它会序列化对象,这我可以接受。b.它不能以嵌套方式追加对象,它只是将一个列表嵌套在另一个列表中,而没有子列表。它显示的数据如下所示(仅限于欧洲,这里没有一个巨大的例子):
{
"id":1,
"region":"world",
"get_all_children":[
[
{
"id":2,
"region":"europe"
}
],
[
[
{
"id":5,
"region":"belgium"
}
],
[
{
"id":6,
"region":"germany"
}
],
[
{
"id":7,
"region":"spain"
}
]
]
]
}
现在的数据是好的,除了在Europe之后,它没有开始在同一个数组中嵌套子数组,它只是为子数组开始一个新的数组,并将它们与外部列表一起追加。它基本上添加了一个嵌套结构,而没有将其嵌套在父数组中。
"我们的问题"
我们如何返回在'我们的目标'中提到的这个区域数据的输出,它拥有一个树结构,去一个未知数量的层次深?当然,它是有限的深度。
我必须遵循的唯一约束是我不能编辑视图部分!
1条答案
按热度按时间pcww981p1#
您可以在序列化器上使用depth属性,例如
或者在序列化程序上使用to_representation方法:
因此,这将允许您使用模型上的
related_name
集以及parent
来查询children