首页 > 解决方案 > 如何在 Django 中执行昂贵操作的循环期间跳过已删除的模型?

问题描述

我有一个名为设备的模型。每个设备都有一个data_downloaded()anddata_uploaded()方法,它在数据库中查找与该设备相关的所有记录,并总结他们使用的数据。每个设备都可能有数千条记录,需要汇总以计算其使用情况。我的模型如下所示:

class Device(models.Model):
    ...
    mac_address = models.CharField(...)
    data_downloaded_cached = models.BigIntegerField(...)
    data_uploaded_cached = models.BigIntegerField(...)

    def data_downloaded(self):
        return DataRecord.objects.filter(mac_address=self.mac_address, direction="download").aggregate(data=Sum('data')).get("data", 0.00) or 0.00

    def data_uploaded(self):
        return DataRecord.objects.filter(mac_address=self.mac_address, direction="upload").aggregate(data=Sum('data')).get("data", 0.00) or 0.00

class DataRecord(models.Model):
    timestamp = models.DateTimeField(...)
    mac_address = models.CharField(...)
    direction = models.CharField(...)
    data = models.BigIntegerField(...)

由于device.data_downloaded()device.data_uploaded()是昂贵的操作,可能需要一分钟的时间来计算(需要聚合大量数据库行),所以我不能在加载模板时直接调用这些方法,所以我缓存了这些值。后台进程运行以下代码以每隔几分钟更新这些缓存值:

for device in Device.objects.all():
    device.data_downloaded_cached = device.data_downloaded()
    device.data_uploaded_cached = device.data_uploaded()
    device.save()

当模板显示设备列表以及每个设备的下载和上传值时,它们可以只使用缓存的值,而不是尝试即时运行这些昂贵的操作,这将导致模板永远加载用户的浏览器。

我遇到的问题是:

我显然不关心更新最近删除的设备的缓存值。我也不想在这些昂贵的操作发生时一次锁定数据库几分钟。如何确保跳​​过已删除的设备?

注意:可以在昂贵的操作开始之前或之后删除设备。我关心的主要事情是确保device.save()不会重新创建设备。如果我能确保在这些操作开始之前已删除的设备上不会执行昂贵的操作,那就太好了。如果没有,我只需要确保已删除的设备不会被重新创建device.save()

编辑:根据 Willem Van Onsem 的建议,我可以这样做:

totals = DataRecord.objects.values('mac_address').order_by('mac_address').annotate(downloaded=Sum('data', filter=Q(direction="download"))).annotate(uploaded=Sum('data', filter=Q(direction="upload")))

updates = []
for device in totals:
    dev = Device.objects.filter(mac_address=device['mac_address']).first()
    if dev:
        dev.data_downloaded_cached = device["downloaded"]
        dev.data_uploaded_cached = device["uploaded"]
        updates.append(dev)

Device.objects.bulk_update(updates, ['data_downloaded_cached', 'data_uploaded_cached'])

听起来对吗?

标签: djangopython-3.x

解决方案


推荐阅读