Аннотация корневого родителя на рекурсивной модели django - PullRequest
0 голосов
/ 12 сентября 2018

У меня есть рекурсивная модель Case (модель имеет собственную ссылку, называемую родительской), и я хочу аннотировать запросы в наборе запросов с корневым родителем.

Итак, если у меня есть корень A с дочерним B, у которого есть дочерний C, я хочу, чтобы набор запросов, содержащий все три, имел ссылку на A. Я создал sql, который выполнил это для отдельного Case, но яне могу понять, как аннотировать набор запросов с ним.Я экспериментирую с подклассом 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"

Ход выполнения: Iтеперь я могу аннотировать набор запросов с помощью запроса, но не могу получить ссылку для каждого дела, переданного запросу

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'

1 Ответ

0 голосов
/ 13 сентября 2018

Решение найдено:

Мне пришлось вставить ссылку на внешний Case в sql, после чего 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, для которого нужно найти корень

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...