Django 2.1+ массовое обновление записей с количеством связанных записей? - PullRequest
1 голос
/ 24 апреля 2019

Я пытаюсь массово обновить все мои записи в таблице A с количеством связанных записей в таблице B.

Я хотел бы сделать что-то вроде:

from django.db.models import Subquery, OuterRef, Count


table_b_subquery = TableB.objects.filter(a_id=OuterRef('id'))

TableA.objects.all().update(table_b_count=Count(Subquery(table_b_subquery)))

Это было бы эквивалентно этому N-BULK методу:

# Non-Bulk

for record in TableA.objects.all():
  record.table_b_count = record.table_b_set.count()

Ошибка, которую я получаю, пытаясь массовым методом:

*** django.core.exceptions.FieldError: Aggregate functions are not allowed in this query

Как мне, казалось бы, просто считатьсвязанных записей в массовом обновлении?В идеале я хотел бы также применить простой фильтр полей к счетчику таблицы B.

Ответы [ 2 ]

1 голос
/ 24 апреля 2019

Вам нужен подзапрос для подсчета (а не только счетные объекты), что немного затрудняет, поскольку регулярные агрегатные запросы, такие как count() или aggregate(), имеют тенденцию выполняться немедленно, тогда как подзапросы должны быть ленивыми. Вот почему annotate() обходной путь ниже необходим:

from django.db.models import Subquery, OuterRef, Count

table_b_subquery = Subquery(TableB.objects
    .filter(a_id=OuterRef('id'))
    .values('a_id')
    .annotate(cnt=Count('a_id'))
    .values('cnt')
)

TableA.objects.update(table_b_count=table_b_subquery)
0 голосов
/ 24 апреля 2019

Ответ Эндре - это то, что я ищу! Я только что нашел новую функцию в Django 2.2, которую, возможно, стоит использовать, и я в конфликте. Я не уверен, что лучше.

Django 2.2 имеет bulk_update

https://docs.djangoproject.com/en/2.2/ref/models/querysets/#django.db.models.query.QuerySet.bulk_update

Так что с bulk_update на мой вопрос я бы сделал:

records = []
for record in TableA.objects.all():
  counted_record = record.table_b_count = record.table_b_set.count()
  records.append(counted_record)

TableA.objects.bulk_update(records, ['table_b_count'], batch_size=100000) 

# This is acting on Table A with 1,000,000 rows and Table B with 5,000,000 rows.

У кого-нибудь есть мысли о том, лучше ли в этом случае ответ Эндре или новый метод Django 2.2 с миллионами строк?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...