【问题标题】:How to efficiently clear nested many to many relationship in Django?如何有效地清除 Django 中嵌套的多对多关系?
【发布时间】:2019-03-27 22:04:38
【问题描述】:

我的代码包含嵌套了多对多关系的模型,我需要清除关系,但是我的解决方案真的很慢,因为它会产生大量的 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()

这实际上有效,并删除了与我们选择的父级关联的子级的所有子级与孙子级的关联。但是在我的情况下,每个父母通常有超过 5k 个孩子,每个孩子大约有 2 个孙子。但这会产生大量的 sql 查询,并且会超时。

我想知道是否有任何有效的方法可以批量或通过某种预取来执行此操作。

** 注意:我只想清除关系,不想删除对象本身。

【问题讨论】:

  • 您能展示ChildGrandChild 模型(或至少定义两者之间关系的部分)吗?如果它是一对多或多对多,它会有所不同,你的问题在这方面有点令人困惑。
  • @EndreBoth 我刚刚进行了编辑。

标签: django django-models orm


【解决方案1】:

对于 M2M 关系,您可以通过可以从任何子实例(不管是哪个)访问的中间表在一个查询中完成它:

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

您还可以通过将Parents 的查询集传递给过滤器来删除多个父级的关系:

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

【讨论】:

  • 可能有很多孙子,而不仅仅是一个。我需要清除所有孙子的子孙关系。
  • 重申一下,您删除了所有受影响孙子的关联,而不仅仅是您用来获取对直通表的引用的 a_grandchild
  • 这并没有删除对象,只是删除了关系?
  • 不,它不会删除任何ParentChildGrandchild。它确实删除了行,但中间表中的行表示ChildGrandchild之间的关系。
  • 好的!现在唯一的问题是找到a_grandchild 有点尴尬。刚刚给家长的难题是我选择哪个a_grandchild 这样做?有什么建议吗?
【解决方案2】:

假设您在 GrandChildChild 模型上有 ForeignKey,您可以使用如下内容:

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

这将在表之间进行链连接并向 SQL DB 发出一个删除命令,而不是为每个child in children 发出一个命令。

编辑:明确关系

如果你想清除grand_child.parent的关系,那么做一个update

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

希望对你有帮助!

【讨论】:

  • 我不想删除孙子,只想清除关系。
  • 那么你需要在上面做一个.update(parent=None),而不是delete()。我已经更新了我的答案。
  • 我已更新问题以显示模型。我需要明确的不是父母,而是GrandChild模型中的grandchild_parents。
  • 更新您的问题后,您似乎有 M2M 关系,而不是 One2M。想法是一样的,实现方式是 Endre Both 写的。
猜你喜欢
  • 2015-01-06
  • 2014-12-11
  • 1970-01-01
  • 2016-07-30
  • 1970-01-01
  • 2020-11-22
  • 2019-01-24
  • 2021-04-15
  • 2015-08-22
相关资源
最近更新 更多