Как добавить «аннотировать» данные в запрос с несколькими «значениями» с django моделями? - PullRequest
1 голос
/ 08 апреля 2020

Пример модели :

class A(models.Model):
    id = models.CharField(max_length=255, primary_key=True, default=make_uuid, editable=False)
    b = models.IntegerField()

Цель :
Мне нужно получить список, который будет содержать id, b и same_b_total.

например, возвращается следующий набор типов:

a = list(models.Cell.objects.all().values("b").annotate(same_b_total=Count("b")))
print(a)  # [{"b": 1, "same_b_total": 5}, {"b": 2, "same_b_total": 3}]

Когда я добавляю id в .values("b", "id"), возвращается список со следующими данными

[{'b': 1, 'id': '<some uuid>', 'same_b_total': 1}, {'b': 1, 'id': '<some uuid2>', 'same_b_total': 1}, {'b': 2, 'id': '<some uuid3>', 'same_b_total': 1}, ...]

Как изменить запрос для получения правильного same_b_total для каждой записи? Как:

[{'b': 1, 'id': '<some uuid>', 'same_b_total': 5}, {'b': 1, 'id': '<some uuid2>', 'same_b_total': 5}, {'b': 2, 'id': '<some uuid3>', 'same_b_total': 3}, ...]

Пример таблицы:
id (uuid) | b

uuid-1 | 1
uuid-2 | 1
uuid-3 | 2
uuid-4 | 1
uuid-5 | 1
uuid-6 | 1
uuid-7 | 2
uuid-8 | 2

1 Ответ

2 голосов
/ 08 апреля 2020

Объяснение

Использование комбинации OuterRef и Subquery - это то, что вы ищете. Для указанного c целочисленного значения для поля b вам необходимо получить количество всех существующих строк. При замене целочисленного значения c на OuterRef('b') результат преобразуется в подзапрос. (вместо обычного набора запросов)

Не то чтобы sub является подзапросом и не существует сам по себе.

sub = A.objects.filter(b=OuterRef('b')).values('b').annotate(same_b_count=Count('id'))

Нам нужно вставить sub в другой запрос. Получение справки от Django документов о комбинации Subquery и Outerref приводит к:

A.objects.annotate(same_b_count=Subquery(sub.values('same_b_count'))).values('id', 'b', 'same_b_count')

Заключение

Объединение двух фрагментов из объяснения:

sub = A.objects.filter(b=OuterRef('b')).values('b').annotate(same_b_count=Count('id'))
A.objects.annotate(same_b_count=Subquery(sub.values('same_b_count'))).values('id', 'b', 'same_b_count')

приведет к выводу:

<QuerySet [{'id': 1, 'b': 1, 'same_b_count': 3}, {'id': 2, 'b': 1, 'same_b_count': 3}, {'id': 3, 'b': 1, 'same_b_count': 3}, {'id': 4, 'b': 3, 'same_b_count': 1}, {'id': 5, 'b': 4, 'same_b_count': 2}, {'id': 6, 'b': 4, 'same_b_count': 2}, {'id': 7, 'b': 6, 'same_b_count': 1}]>
...