【问题标题】:Django - Perform queryset level task before deleteDjango - 在删除之前执行查询集级别任务
【发布时间】:2016-01-11 07:06:06
【问题描述】:

我有以下型号:

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:

我刚刚注意到我想做的事情有一个缺陷。我假设要删除的图像属于同一台相机,但是如果它们不是来自同一台相机,那么这种方法将不起作用。我想实现我想要的唯一方法是在听众中......

【问题讨论】:

  • 必须在模型级别发生吗?批量删除图像会发生这种情况吗?或者我应该问图像是如何删除的?
  • 你使用的是什么版本的 Django? Since 1.9 delete 返回带有model label -> deleted rows count 的字典。
  • 好吧,我想做的是,当我使用 .delete() 时,计数器会更新,因此当在管理员、shell 等中删除图像时,计数器会自动更新。
  • 我使用的是 django 1.5

标签: django django-signals django-managers


【解决方案1】:

您可以使用查询集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()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-18
    • 1970-01-01
    • 1970-01-01
    • 2015-02-02
    • 2011-06-01
    • 2010-10-11
    • 2019-02-22
    相关资源
    最近更新 更多