Аннотация с подзапросом с множественным результатом в Django

Я использую базу данных postgresql в своем проекте, и я использую приведенный ниже пример из документации django.

from django.db.models import OuterRef, Subquery
newest = Comment.objects.filter(post=OuterRef('pk')).order_by('-created_at')
Post.objects.annotate(newest_commenter_email=Subquery(newest.values('email')[:1]))

но вместо последнего письма комментатора мне нужны последние два письма комментатора. Я изменился[:1] к [:2] но возникло это исключение: ProgrammingError: more than one row returned by a subquery used as an expression.

1 ответ

Вам нужно каким-то образом агрегировать результаты подзапроса: возможно, используя ARRAY() построить.

Вы можете создать подкласс Subquery сделать это:

class Array(Subquery):
    template = 'ARRAY(%(subquery)s)`
    output_field = ArrayField(base_field=models.TextField())

(Вы можете использовать более автоматический метод получения поля вывода, но пока это должно работать для вас: см. https://schinckel.net/2019/07/30/subquery-and-subclasses/ для получения дополнительных сведений).

Тогда вы можете использовать:

posts = Post.objects.annotate(
    newest_commenters=Array(newest.values('email')[:2]),
)

Причина этого в том, что коррелированный подзапрос в postgres может возвращать только одну строку с одним столбцом. Вы можете использовать этот механизм для работы с несколькими строками и, возможно, использовать конструкцию JSONB, если вам нужно несколько столбцов.

Другие вопросы по тегам