【问题标题】:How to bulk-associate an object to multiple objects that have ManyToManyField?如何将一个对象批量关联到具有 ManyToManyField 的多个对象?
【发布时间】:2020-07-08 11:27:22
【问题描述】:

我有一个看起来像这样的模型:

class Keyword(models.Model):
    name = models.CharField(unique=True)

class Post(models.Model):
    title = models.CharField()
    keywords = models.ManyToManyField(
        Keyword, related_name="posts_that_have_this_keyword"
    )

现在我想将 错误命名 Keyword 的所有 Posts 迁移到一个新的正确命名 Keyword。并且有多个错误命名Keywords。

我可以执行以下操作,但会导致大量 SQL 查询。

for keyword in Keyword.objects.filter(is_wrongly_named=True).iterator():
    old = keyword
    new, _ = Keyword.objects.get_or_create(name='some proper name')
    for note in old.notes_that_have_this_keyword.all():
        note.keywords.add(old)
    old.delete()

有没有办法在最小化执行的 SQL 查询的同时实现这一点?

我更喜欢 Django ORM 解决方案而不是原始 SQL 解决方案,因为我直接进入 Django ORM 没有深入研究 SQL,对 SQL 不是很熟悉。

谢谢。

【问题讨论】:

  • 你不能只重命名关键字吗?
  • @IainShelvington 我不能,因为已经存在带有'some proper name' 的关键字。简单地重命名它们会导致IntegrityError
  • 这能回答你的问题吗? How to update manytomany field in Django?
  • @IainShelvington 它看起来像我在这个问题中发布的代码。对我没有帮助。

标签: python sql django


【解决方案1】:

如果您想使用 M2M 关系执行批量操作,我建议您直接对连接两个对象的表进行操作。 Django 允许您通过在对象的 M2M 属性上使用 through 属性来访问此匿名表。

因此,要获取连接关键字和帖子的表格,您可以引用 Keyword.posts_that_have_this_keyword.throughPost.keywords.through。我建议您为此分配一个命名良好的变量:

KeywordPost = Post.keywords.through

一旦您持有该表,就可以执行批量操作。

批量删除不良条目

KeywordPost.objects.filter(keyword__is_wrongly_named=True).delete()

批量创建新条目

invalid_keyword_posts = KeywordPost.objects.filter(keyword__is_wrongly_named=True)
post_ids_to_update = invalid_keyword_posts.values_list("post_id", flat=True)
new_keyword_posts = [KeywordPost(post_id=p_id, keyword=new_keyword) for p_id in post_ids_to_update]
KeywordPost.objects.bulk_create(new_keyword_posts)

基本上,您可以访问 ORM 在此连接表上提供的所有功能。您应该能够以这种方式获得更好的性能。

您可以在此处阅读有关 through 属性的更多信息:https://docs.djangoproject.com/en/3.0/ref/models/fields/#django.db.models.ManyToManyField.through

祝你好运!

【讨论】:

  • 这正是我想要的。现在我更好地掌握了Through 模型的作用。谢谢。
  • 这是一个超级强大的概念,希望你以后能用得上!
猜你喜欢
  • 2017-02-14
  • 2013-05-06
  • 2012-03-21
  • 1970-01-01
  • 2019-06-11
  • 1970-01-01
  • 1970-01-01
  • 2010-10-20
  • 1970-01-01
相关资源
最近更新 更多