【问题标题】:Recursive QuerySet with django使用 django 的递归查询集
【发布时间】:2017-10-09 18:42:23
【问题描述】:

我有这个模型引用自己以允许构建一棵树:

class PartCategory(models.Model):
    parent = models.ForeignKey('PartCategory', on_delete=models.DO_NOTHING, null=True, default=None, blank=True)
    name = models.TextField()

我现在有一个 SQL 查询,可以在一次选择中获取一个元素及其所有子元素(在本例中为 id=64 的元素):

WITH RECURSIVE
  under_partcategory(id,name, parent_id,level) AS (
    select api_partcategory.id,api_partcategory.name,api_partcategory.parent_id,0 from api_partcategory where api_partcategory.id=64
    UNION ALL
    SELECT api_partcategory.id,api_partcategory.name,api_partcategory.parent_id, under_partcategory.level+1
    FROM api_partcategory JOIN under_partcategory ON api_partcategory.parent_id=under_partcategory.id
    ORDER BY 2
  )
SELECT * FROM under_partcategory;

我正在寻找一种在 QuerySet 中表达此查询的方法,以允许从我的模型中添加过滤选项和字段构造,但我不太清楚这是否可行。

我可以构造一个复合 QuerySet,由我的模型构建的某种原始查询组成,同时允许使用 filterorder_by 功能吗?

编辑:

更具体地说,我想要一个 QuerySet 我可以使用这个 whay:

PartCategory.recursive.filter(64)

在内部,它将通过使用 PartCategory 模型中的元素替换所有包含的部分来构建请求:

WITH RECURSIVE
  under_{model name}({model fields},level) AS (
    select {model fields},0 from {model name} {where {model name}.id=64 #extracted from filter}
    UNION ALL
    SELECT {model fields}, under_{model_name}.level+1
    FROM {model name} JOIN under_{model_name} ON {model_name}.parent_id=under_{model_name}.id
    ORDER BY 2
  )
SELECT * FROM under_{model_name};

我正在使用自定义管理器来尝试构建它,但现在我不知道如何从我的模型构建 {model fields} 以及如何返回符合 filter 的对象。

编辑 2:

正如 colwin 所说,我使用 django-mptt 完成了它,但与我最初的想法并不完全一样。

我的django-mptt 模型变为:

from mptt.models import MPTTModel, TreeForeignKey

class PartCategory(MPTTModel):
    parent = TreeForeignKey('self', null=True, blank=True, related_name='children', db_index=True)
    name = models.TextField()
    class MPTTMeta:
        order_insertion_by = ['name']

现在要提取我的项目 64 及其所有子项:

categories = PartCategory.objects.get(id=64).get_descendants(include_self=True)

这很简单!

【问题讨论】:

    标签: django django-queryset recursive-query


    【解决方案1】:

    这不适合你吗?

    parts = PartCategory.objects.raw('''
        WITH RECURSIVE
        under_partcategory(id,name, parent_id,level) AS (
        select   api_partcategory.id,api_partcategory.name,api_partcategory.parent_id,0 from api_partcategory where api_partcategory.id=64
        UNION ALL
        SELECT api_partcategory.id,api_partcategory.name,api_partcategory.parent_id, under_partcategory.level+1
        FROM api_partcategory JOIN under_partcategory ON api_partcategory.parent_id=under_partcategory.id
        ORDER BY 2
      )
    SELECT * FROM under_partcategory;
    ''')
    

    你也可以看看https://github.com/django-mptt/django-mptt

    【讨论】:

    • 这是我的第一次尝试,我想更进一步(我将我的问题编辑得更具体)
    • 你有机会看看 django-mptt 吗?它专为处理像您的情况一样的树木而设计。我没有太多或最近使用它,但它看起来适合你需要做的事情。
    • 绝对是的,完全符合我的需要,谢谢!
    猜你喜欢
    • 2017-12-10
    • 1970-01-01
    • 2011-03-21
    • 2014-08-11
    • 1970-01-01
    • 2014-01-25
    • 2014-10-29
    • 1970-01-01
    • 2019-10-06
    相关资源
    最近更新 更多