我有两个模型 - 照片和标签 - 通过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: delete M2M orphan entries?
我们的解决方案目前看起来像这样:
for tag in Tag.objects.all():
if not tag.photo_set.select_related(): tag.delete()
然而,随着数据库的增加,这个脚本的运行时变得非常令人沮丧:-P是否有一种有效的方法从标签表中获取所有标签ID的列表,然后是许多标签ID的列表 - to-many table创建一个交集列表?
答案 0 :(得分:3)
尝试使用/ intermediate table
进行子查询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()
答案 1 :(得分: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()
通过这种方式,对数据库的查询变得更小更快。
答案 2 :(得分:0)
我找到了一种“实时”执行此操作的方法:
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时, 此功能称为。