Django - 删除前执行查询集级别任务

时间:2015-10-13 13:39:42

标签: django django-signals django-managers

我有以下型号:

class Camera(models.Model)
    deleted_images_counter = models.IntegerField(...)

class Image(models.Model)
    image = models.ImageField(....)
    camera = models.ForeignKey(Camera)

现在,我想在删除一张或多张图片时更新相机deleted_images_counter字段。

我虽然使用信号:

@receiver(pre_delete, sender=Image,dispatch_uid="test" )
def update_deleted_images_counter(sender, instance, using, **kwargs):
    camera = instance.camera
    camera.counter = camera.counter + 1
    camera.save()

但问题是它在对象级别工作,所以如果我想删除200,000张图像,它必须对相机进行相同数量的更新。

有没有办法创建一个新的方法或信号,我可以做这样的事情?

images_to_delete = Images.objects.filter(...)
images_to_delete.delete()    

#some method of something
def delete(queryset, ....):
    #update the counter
    camera.deleted_images_counter = camera.deleted_images_counter + queryset.count()
    camera.save()

    #continue with the delete...
    queryset.delete()

谢谢!

编辑1:

我刚刚注意到了我想做的事情的缺陷。我假设要删除的图像属于同一台摄像机,但如果它们不是来自同一台摄像机,则此方法不起作用。实现我想要的唯一方法就是在听众中我猜...

1 个答案:

答案 0 :(得分:0)

您可以使用queryset annotate方法获取查询集中每个摄像头的图像数量。

有关详细信息,请参阅Django docs。他们的例子使用的模型与你的非常相似:

# Each publisher, each with a count of books as a "num_books" attribute.
>>> from django.db.models import Count
>>> pubs = Publisher.objects.annotate(num_books=Count('book'))
>>> pubs
[<Publisher BaloneyPress>, <Publisher SalamiPress>, ...]
>>> pubs[0].num_books
73

# The top 5 publishers, in order by number of books.
>>> pubs = Publisher.objects.annotate(num_books=Count('book')).order_by('-num_books')[:5]
>>> pubs[0].num_books
1323

在我的帽子顶部,您可以执行类似

的操作
# this should return a list of dicts of format {'camera': int, 'images_to_delete': int}
aggregated_queryset = image_queryset.values('camera__id').annotate(images_to_delete=Count('id'))

for record in aggregated_queryset:
    camera = Camera.objects.get(id=record.get('camera'))
    images_to_delete = record.get('images_to_delete')
    camera.deleted_images_counter += images_to_delete
    camera.save()

image_queryset.delete()