有效地删除在Django孤立M2M对象/标签(Efficiently delete orphaned

2019-06-24 11:31发布

我有两个型号 - 照片和标签 - 它们通过ManyToManyField连接。

class Photo(models.Model):
    tags = models.ManyToManyField(Tag)

class Tag(models.Model):
    lang = models.CharField(max_length=2)
    name_es = models.CharField(max_length=40)
    name_en = models.CharField(max_length=40)

每过一段时间,我们得到孤立的标签,未提及任何更多的任何照片。 有没有删除这些标签的有效途径? 我知道这样的回答: Django的:删除M2M孤儿项?

而我们的解决方案看起来像这样的时刻:

for tag in Tag.objects.all():
    if not tag.photo_set.select_related(): tag.delete()

然而,随着数据库,该脚本的运行变得令人不安的高:-P有正从标签表中的所有标签ID的列表的有效方式,然后从所有的标签ID的列表许多一对多表中创建一个交叉路口明细表?

Answer 1:

试试子查询W /中间表

qs = Tag.objects.exclude(pk__in=Book.tags.through.objects.values('tag'))

# then you could
qs.delete()

# or if you need to trigger signal per item
for x in qs:
    x.delete()


Answer 2:

我们必须进一步提高这个任务的表现,让我修改OKM的解决方案了一下:

    all_tag_pks = Tag.objects.values_list('pk', flat=True)
    used_tag_pks = Photo.tags.through.objects.values_list('tag', flat=True)
    Tag.objects.filter(pk__in=list(set(all_tag_pks) - set(used_tag_pks))).delete()

由,查询到数据库中获取更小,速度更快了很多。



Answer 3:

我发现了一种“实时”要做到这一点:

from django.db.models.signals import m2m_changed
from django.dispatch import receiver

class Photo(models.Model):
    tags = models.ManyToManyField(Tag)

class Tag(models.Model):
    lang = models.CharField(max_length=2)

@receiver(m2m_changed, sender=Photo.tags.through)
def delete_orphean_dateranges(sender, **kwargs):
    # when something is removed from the m2m:
    if kwargs['action'] == 'post_remove':  
        Tag.objects.filter(pk__in=kwargs['pk_set'], photo_set=None).delete()
        # select removed tags and check if they are not linked
        # to any Photo, and delete it

这样,每个删除从M2M一个标签,当你编辑照片的M2M时间,这个函数被调用。



文章来源: Efficiently delete orphaned m2m objects/tags in Django