Как эффективно очистить вложенные отношения многих со многими в Джанго? - PullRequest
1 голос
/ 28 марта 2019

У меня есть код с моделями, которые вложили отношения многие ко многим, и мне нужно очистить отношения, однако решение, которое у меня есть, действительно медленное, так как оно выполняет тонны SQL-запросов.

У меня есть три модели: Parent, Child, GrandChild. У родителя может быть много детей, а у ребенка много внуков. Что мне нужно сделать, это удалить отношения ребенка и внука с учетом родителей.

class Parent:
    children = models.ManyToManyField(Child)

class Child:
    pass

class GrandChild:
    # Can have many parents (aka. the child model) 
    parents = models.ManyToManyField(Child)

parent = models.Parent.objects.get(id=1)
children = parent.children.all()
for child in children:
    children.grandchild_set.clear()

Это на самом деле работает и устраняет все ассоциации ребенка с внуком для ребенка, связанные с выбранным нами родителем. Однако в моем случае на одного родителя обычно приходится более 5 тысяч детей, а на каждого ребенка приходится около двух внуков. Но это делает тонны SQL-запросов и время ожидания.

Мне интересно, есть ли какой-нибудь эффективный способ сделать это навалом или какой-либо предварительной загрузкой.

** Примечание: я хочу только очистить отношения, не хочу удалять сами объекты.

Ответы [ 2 ]

1 голос
/ 28 марта 2019

Для отношений M2M вы можете просмотреть промежуточную таблицу, к которой вы можете получить доступ из любого дочернего экземпляра (неважно, какой), чтобы выполнить это всего за один запрос:

a_grandchild = GrandChild.objects.filter(child__parent=your_parent_id)[0]
a_grandchild.parents.through.objects.filter(child__parent=your_parent_id).delete()

Вы также можете удалить отношения для более чем одного родителя, передав в фильтр набор запросов Parent s:

parents = Parent.object.filter(...)
GrandChild.objects.filter(child__parent=parents[0])[0] \
    .through.objects.filter(child__parent__in=parents).delete()

0 голосов
/ 28 марта 2019

Если у вас есть модели ForeignKey на GrandChild и Child, вы можете использовать что-то вроде этого:

GrandChild.objects.filter(parent__parent__id=1).delete()

Это создаст цепное соединение между таблицами и выдаст одну команду удаления в БД SQL вместо одной команды для каждого child in children.

Редактировать: очистить отношения

Если вы хотите очистить отношения grand_child.parent, выполните update.

GrandChild.objects.filter(parent__parent__id=1).update(parent=None)

Надеюсь, это поможет!

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