如何将一个对象大容量关联到多个具有ManyToManyField的对象



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

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的所有Post迁移到新的正确命名的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查询的同时实现这一点?

与原始SQL相比,我更喜欢Django ORM解决方案,因为我没有深入研究SQL,也不太熟悉SQL,就直接进入了Django ORM。

谢谢。

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

因此,要获得连接Keywords和Posts的表,可以引用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

祝你好运!

最新更新