Efficiently delete orphaned m2m objects/tags in Django

前端 未结 3 1527
遇见更好的自我
遇见更好的自我 2021-01-05 17:06

I have two models - Photo and Tag - which are connected via a ManyToManyField.

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

class Tag(m         


        
相关标签:
3条回答
  • 2021-01-05 17:48

    We've had to further improve performance of this task, so I modified okm's solution a bit:

        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()
    

    By that, the query to the database gets a lot smaller and faster.

    0 讨论(0)
  • I found a way to do this "in real time":

    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
    

    This way, each time you edit the Photo's m2m when deleting a tag from the m2m, this function is called.

    0 讨论(0)
  • 2021-01-05 18:12

    Try sub-query w/ 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()
    
    0 讨论(0)
提交回复
热议问题