Django - Custom Cross Join не работает из-за ожидаемых полей join для условия on

Я создал пользовательский класс для реализации перекрестного соединения в Django, используя следующий код

class CrossJoinToFunction(Join):
    def __init__(self, table_name, parent_alias, table_alias, join_type,
                 join_field, nullable, filtered_relation=None, table_function_params: List[Any] = None):
        super().__init__(table_name, parent_alias, table_alias, join_type,
                     join_field, nullable, filtered_relation)
        self.table_function_params = table_function_params  # type: List[Any]

    def as_sql(self, compiler, connection):
        sql, params = super().as_sql(compiler, connection)

        table_function_placeholders = []
        table_function_params = []
        for param in self.table_function_params:
            if hasattr(param, 'as_sql'):
                param_sql, param_params = param.as_sql(compiler, connection)
            else:
                param_sql = '%s'
                param_params = [param]
            table_function_placeholders.append(param_sql)
            table_function_params += param_params

        sql = '{} {}({}) {}'.format(
            self.join_type,
            compiler.quote_name_unless_alias(self.table_name),
            ', '.join(table_function_placeholders),
            self.table_alias
        )
        return sql, table_function_params + params

который можно использовать в пользовательском запросе следующим образом

self.alias_map[alias] = CrossJoinToFunction(
    join.table_name, join.parent_alias, join.table_alias, join.join_type, None,
    None, None, resolved_params
)

Желаемый результат в SQL будет следующим

select 
  fb.id
  cf.some_returned_value
from foobar fb
cross join custom_function(params..) as cf

Проблема возникает из-за того, что Django всегда ожидает наличия поля join_field для всех соединений. Это противоречит перекрестным соединениям, поскольку они не имеют условия on.

Добавление бросков join.join_field в CrossJoinToFunction приводит к следующей ошибке django

self.alias_map[alias] = CrossJoinToFunction(
    join.table_name, join.parent_alias, join.table_alias, join.join_type, join.join_field,
    join.nullable, join.filtered_relation, resolved_params
)

  File "/Users/timmcgee/Documents/main-site/project/models.py", line 1493, in setup_joins
    join.table_name, join.parent_alias, join.table_alias, join.join_type, join.join_field,
AttributeError: 'BaseTable' object has no attribute 'join_field'

передача None для поля join_field (так как для перекрестных соединений его нет), приводит к следующей ошибке

  File "/Users/timmcgee/Documents/main-site/venv/lib/python3.6/site-packages/django/db/models/sql/query.py", line 1067, in resolve_expression
    (isinstance(table, Join) and table.join_field.related_model._meta.db_table != alias) or
AttributeError: 'NoneType' object has no attribute 'related_model'

Это происходит из https://github.com/django/django/blob/main/django/db/models/sql/query.py. resolve_expression функция, утверждающая для join_field.

Выполнение перекрестного соединения чисто на python не является вариантом (так как это предложение я видел везде, где говорилось о перекрестных соединениях с Django) из-за производительности. Операция должна быть выполнена на уровне базы данных.

Вернуться на верх