Фильтрация по нескольким полям из подзапроса, в котором нет связанного поля
Я пытаюсь найти переносимый способ выражения следующего запроса фильтрации записей с помощью 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-бэкендах.