Django добавляет объекты в Related Manager при создании - PullRequest
0 голосов
/ 16 мая 2018

Рассмотрим простые отношения ForeignKey:

class A(Model):
    pass
class B(Model):
    a = ForeignKey(A)

У меня есть представление API, которое создает A и набор B на основе внешних данных (данные НЕ передаются от пользователя), затем сериализует созданные объекты и возвращает сериализованные данные. Мой код создания объекта выглядит примерно так:

a = A()
a.b_set.bulk_create(B(a=a) for b in [...])

Моя проблема в том, что это не добавляет объекты B в b_set a, поэтому, если бы я должен был запустить

print(a.b_set.all())

после этого он снова запросит БД для получения b_set. Это не нужно, хотя, потому что у меня уже есть весь b_set, как я только что создал его. Я делаю это с рядом вложенных объектов, так что это приводит к большому количеству ненужных запросов. Мой текущий обходной путь - после создания выполнить запрос вроде

A.objects.prefetch_related('b_set').get(a=a.id)

затем сериализатор, который выбрал объект. Это ограничивает сериализацию только одним ненужным запросом, но я бы тоже хотел исключить этот. Мне кажется, что должен быть способ кэширования созданных объектов B на и Любая необходимость снова ударить БД во время сериализации.

Ответы [ 2 ]

0 голосов
/ 22 мая 2018

После некоторого изучения исходного кода QuerySet и Model я решил, что мой лучший / единственный вариант - напрямую изменять _prefetched_objects_cache для каждого объекта. Определенно не красиво, но это работает. Вот суть того, что я сделал:

a = A()
b_set = a.b_set.bulk_create(B(a=a) for b in [...])
a._prefetch_related_cache = {}
a._prefetch_related_cache['b_set'] = b_set

Это гарантирует, что все созданные B кэшируются на a. Обратите внимание, что если B имеет автоматически созданное поле первичного ключа, эти поля не будут заполняться объектами, возвращаемыми bulk_create с большинством внутренних компонентов. К счастью, я использую PostgreSQL, который возвращает auto-PK с bulk_create, так что для меня это не проблема.

0 голосов
/ 16 мая 2018

Я считаю, что вам нужно сначала выполнить a.save(), прежде чем вы сможете bulk_create. Вот мои результаты с использованием двух моделей, которые вы описали:

a = A()
a.save()
a.b_set.bulk_create([B(a=a), B(a=a), B(a=a)])    
a.b_set.count()
>>> 3
...