我有一个看起来像这样的模型:
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
。并且有多个被错误命名为Keyword
s.
我可以执行以下操作,但这会导致许多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.through
或Post.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
祝你好运!