django递归模型上根父的注释

问题描述 投票:2回答:1

我有一个递归模型Case(模型有一个名为parent的自引用),我想用root父项注释一个queryset Cases。

因此,如果我有一个带有子C的子A的根A,我希望包含所有三个的查询集具有对A的引用。我已经创建了为单个Case完成此操作的sql,但我无法理解如何注释用它查询。我正在尝试django.db.models.Func的子类,但无法使其工作。

模型:

class Case(CoreModel):
    ... fields ...
    parent = ForeignKey(
        'Case', 
        verbose_name=ugettext_lazy("Parent case"), 
        null=True, 
        blank=True, 
        on_delete=models.SET_NULL,
)

有效的SQL查询:

query = '''
        WITH RECURSIVE Ancestors AS (
              SELECT id, parent_id FROM core_case m where id = %(expressions)s
              UNION ALL
              SELECT m.id, m.parent_id
              FROM Ancestors 
              JOIN core_case m on m.id=Ancestors.parent_id
            )
        SELECT id, parent_id FROM Ancestors WHERE parent_id IS NULL
    '''

当前对Func子类的尝试:

class RootCase(Func):

    template = query

    def __init__(self, *expressions):
        super(RootCase, self).__init__(*expressions, output_field = IntegerField())

测试时

cases = (
    Case
    .objects
    .filter(customer__company=514)
    .annotate(root=RootCase(7401))
 )

它失败:

django.db.utils.ProgrammingError: syntax error at or near "WITH"

进度:我现在能够用查询注释一个查询集,但是我无法获得传递给查询的每个Case的引用

cases = (
    Case
    .objects
    .filter(customer__company=514)
    .annotate(root=RawSQL(query, (7401,))
 )
)

这有效,但始终使用7401的根父进行注释

cases = (
    Case
    .objects
    .filter(customer__company=514)
    .annotate(root=RawSQL(query, (OuterRef('pk'),))

 )
)

这失败了:

django.db.utils.ProgrammingError: can't adapt type 'OuterRef'
python django postgresql
1个回答
0
投票

解决方案:

我不得不在sql中插入外部Case的引用,然后postgres能够为每个Case执行注释

annotate_root_case_query = '''
    WITH RECURSIVE Ancestors AS (
          SELECT id, name, number, parent_id FROM core_case m where id = case_id
          UNION ALL
          SELECT m.id, m.name, m.number, m.parent_id
          FROM Ancestors 
          JOIN core_case m on m.id=Ancestors.parent_id
    )
    SELECT {field} FROM Ancestors WHERE parent_id IS NULL
    '''

queryset = queryset.annotate(
        root_case__number=RawSQL(
                annotate_root_case_query.format(field='number'), ())
        )

case_id是要查找根的Case的id

© www.soinside.com 2019 - 2024. All rights reserved.