我有一个递归模型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'
解决方案:
我不得不在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