#python #django #postgresql #django-orm
Вопрос:
У меня есть объектная модель, в которой Documents
есть длинные текстовые файлы, которые могут иметь Attachments
, и оба набора объектов также могут быть похожи на электронные таблицы Tables
. Каждая таблица содержит прямоугольный массив с текстом. Я хочу, чтобы пользователи могли искать ключевое слово по содержимому таблицы, но результаты будут отображаться в основном документе (поэтому вместо просмотра каждой соответствующей таблицы вы просто увидите документ, в котором больше всего таблиц соответствует вашему запросу).
Ниже вы можете увидеть тестовый запрос, который я пытаюсь выполнить, который в идеальном мире преобразует все содержимое таблицы (во всех вложениях) в одну длинную строку, которую я затем могу передать в поисковый индикатор, чтобы сделать заголовок. По какой-то причине тестовый запрос возвращает таблицы как разные объекты, а не объединенные в одну длинную строку. Я использую пользовательскую функцию, которая имитирует Postgres 13 StringAgg
, как я использую Postgres 10.
Заранее спасибо за вашу помощь, дайте мне знать, если мне понадобится предоставить дополнительную информацию, чтобы повторить это.
мой models.py
:
class Document(AbstractDocument):
tables = GenericRelation(Table)
class Attachment(AbstractDocument):
tables_new = GenericRelation(Table)
main_document = ForeignKey(Document, on_delete=CASCADE, related_name="attachments")
class Table(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.SlugField()
content_object = GenericForeignKey()
content = ArrayField(ArrayField(models.TextField(null=True)))
мой вопрос:
def myStringAgg(field: str):
return Func(
F(field),
Value(" "),
Value(""),
function="array_to_string",
output_field=models.TextField(),
)
s = Document.objects.all()
.annotate(tt=myStringAgg("attachments__tables__content"))
.values_list('tt', flat=True)
# what I get
>>> <DocumentSet ['table1', 'table2']>
# what I want
>>> <DocumentSet ['table1 table2']>
Я использую Django 3.2
и. Postgres 10
Чтобы уточнить, какова моя полная область, вот как будет выглядеть окончательный запрос:
qs = Document.objects.filter(
Q(tables__search_vector=query) |
Q(attachments__tables__search_vector=query)
)
.annotate(rank=rank)
.order_by("-rank")
.annotate(snippet=SearchHeadline(
myStringAgg("attachments__tables__content"),
query, max_fragments=5)
)
Ответ №1:
You can use the join function to create a string from a list:
s = Document.objects.all()
.annotate(tt=myStringAgg("attachments__tables__content"))
.values_list('tt', flat=True)
s = " ". join(list(s))
Комментарии:
1. Это не сработает, так как я передаю полученную строку для дальнейшей обработки SQL (переходя к вызову функции SearchHeadline). Поэтому мне нужно, чтобы соединение произошло в SQL-запросе, а не после.