【问题标题】:Get parent by its children in Django Queryset通过 Django Queryset 中的子项获取父项
【发布时间】:2020-11-15 20:22:36
【问题描述】:

我有这个模型:

Department(models.Model):
    title =  models.CharField(max_length=128)
    reference = models.ForeignKey('self', related_name='reference')

如您所见,此模型的每个对象都可以有父对象,反之亦然。

例如,这些是部门的对象:

id = 1 , title = 'dep 1' , reference_id = Null
id = 2 , title = 'dep 2' , reference_id = 1
id = 3 , title = 'dep 3' , reference_id = Null
id = 4 , title = 'dep 4' , reference_id = 1
id = 5 , title = 'dep 5' , reference_id = 3
id = 6 , tiltl = 'dep 6' , reference_id = 3
id = 7 , title = 'dep 7' , reference_id = 3
id = 8 , title = 'dep 8' , reference_id = 9
id = 9 , title = 'dep 9' , reference_id = Null
id = 10, title = 'dep 10', reference_id = 9

现在我想获取具有此条件的对象列表:Each parent by its children。像这样:

- dep 1 
    dep 2 
    dep 4 
- dep 3 
    dep 5
    dep 6
    dep 7
- dep 9
    dep 8 
    dep 10

我该怎么做? (我可以只用Django ORM 创建这个列表吗?)

更新 这是我的部门级别:

Department_Level = (
    (1, 'headquarters'),
    (2, 'unit'),
    (3, 'center'),
)
level = models.IntegerField(choices=Department_Level,default=.Department_Level[2][0])    

我只想要列表中的第 2 级和第 3 级。

【问题讨论】:

  • 我假设层次结构可以永远存在?因为一个部门可以属于另一个部门。
  • 最好看看像django-mptt 这样实现树结构实用程序的包。
  • 层次结构有 3 个级别。 @WillemVanOnsem
  • 我不能在我的项目中使用这个包。 (公司政策)@WillemVanOnsem
  • 您希望如何返回您的数据?

标签: python django model django-2.0


【解决方案1】:

使用ArrayAgg 可能有效。请尝试一下。

from django.contrib.postgres.aggregates import ArrayAgg


# dept_id is root department id
dept_list = Department.objects.filter(id=dept_id).annotate(reference_list=ArrayAgg('department__reference'))

【讨论】:

    【解决方案2】:

    首先,获取所有对象

    mapper = dict(Department.objects.values_list("id", "reference_id"))
    

    这将产生一个字典(子到父)

    {1: None, 2: 1, ...}
    

    将带有父级的dict转换为子级

    res = dict()
    for child, parent in mapper.items():
         res.setdefault(parent, []).append(child)
    

    现在您可以根据自己的喜好在其上构建数据结构。您还可以通过查找某个项目的所有子项的子项来获取孙子项。

    最好构造一个树形结构,编写一个类方法,返回带有res作为输入的树。

    编辑。为了回答 cmets 中关于 N 级别的问题,我们可以使用树结构而不是普通的 dict,但我们仍然可以使用当前的 dict 结构获取任何级别的所有孙子。下面的代码假设没有循环关系。

    def get_all_grand_children(node_id, n_level) -> List:
        if n_level == 0:
             return []
        output = list()
        for child in res.get(node_id, []):
             output.append(child)
             output.extend(get_all_grand_children(child, n_level - 1)
        return output
    

    【讨论】:

    • 我怎样才能用你的方法找出孙子或孙子(对于 n 级引用)? @vestronge
    • 编辑了答案以添加简短的 sn-p 以将所有孙子提取到某个级别。
    猜你喜欢
    • 1970-01-01
    • 2018-06-04
    • 1970-01-01
    • 1970-01-01
    • 2020-07-01
    • 1970-01-01
    • 2011-04-01
    • 2023-03-06
    • 1970-01-01
    相关资源
    最近更新 更多