Фильтрация по нескольким полям из подзапроса, в котором нет связанного поля

Я пытаюсь найти переносимый способ выражения следующего запроса фильтрации записей с помощью Django ORM.

Намерение состоит в том, чтобы:

  • возьмите подзапрос FilterSpec (например, с общим FilterGroup)
  • найдите все экземпляры Record, где Record.text1 = FilterSpec.r_text1 AND Record.text2 = FilterSpec.r_text2 хотя бы для одного из экземпляров FilterSpec в подзапросе.
  • включите совпадающие FilterSpec.filter_name в возвращаемые экземпляры Record.

Record будет иметь высокую кардинальность, >100 000, после фильтрации обычно <1000. Подзапрос FilterSpec будет иметь низкую кардинальность, обычно <10.

Вот суть моделей:

class RecordGroup(Model):
    name = CharField(unique=True)
    # further data fields

class Record(Model):
    text1 = CharField()
    text2 = CharField()
    group = ForeignKey(RecordGroup)
    # further data fields

class FilterGroup(Model):
    name = CharField(unique=True)

class FilterSpec(Model):
    r_text1 = CharField()
    r_text2 = CharField()
    filter_name = CharField()
    group = ForeignKey(FilterGroup)

Проблема заключается в том, что между полями записи и полями фильтра нет формальной связи. В Record.text1 и Record.text2 будет много повторяющихся значений.

Я нашел или разработал примеры, в которых:

  • здесь сравнивается одно поле
  • где сравниваются два поля путем конкатенации двух полей в одно (но я ожидаю, что это будет медленно при масштабировании)
  • есть Q выражение, перечисляющее FilterSpec подзапрос

Я не нашел способа, чтобы поле типа FilterSpec.filter_name передавалось через него.

Однако на языке SQL это не особенно сложно:

SELECT record.text1, record.text2, record.further_data, filterspec.filter_name, recordgroup.further_data
FROM record
LEFT JOIN filterspec
    ON record.text1 = filterspec.r_text1
    AND record.text2 = filterspec.r_text2
LEFT JOIN filter group
    ON filterspec.group_id = filtergroup.id
LEFT JOIN recordgroup
    ON record.group_id = recordgroup.id
WHERE filtergroup.name = "example-filter-group-17";

Может ли кто-нибудь предложить решение на основе ORM, в идеале избегая сырого SQL или даже .extra() и других методов, которые, вероятно, будут устаревшими? Для меня это должно работать на SQLite (для dev) и с MySQL/MariaDB (prod), но в идеале должно работать на всех SQL-бэкендах.

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