Django queryset - 按列总和过滤/排除

时间:2014-06-22 13:05:57

标签: django django-models django-queryset

对于小型缓存应用程序,我有以下问题/疑问:

模型的一部分:

class CachedResource(models.Model):
    ...
    filesize = models.PositiveIntegerField()
    created = models.DateTimeField(auto_now_add=True, editable=False)
    ...

缓存应该是例如限制为200MB - 并保留最新文件。

如何创建如下的查询集:

CachedResource.objects.order_by('-created').exclude(" summary of filesize < x ")

任何意见都赞赏!

示例:

created             filesize        keep/delete?

2014-06-22 15:00          50        keep    (sum: 50)
2014-06-22 14:50         100        keep    (sum: 150)
2014-06-22 14:40          30        keep    (sum: 180)
2014-06-22 14:30          20        keep    (sum: 200)
2014-06-22 14:20          50        delete  (sum: 250 > 200)
2014-06-22 14:10          10        delete  ...
2014-06-22 14:00         200        delete  ...
2014-06-22 13:50          10        delete  ...
2014-06-22 13:40           2        delete  ...
             ...         ...        ...     ...

3 个答案:

答案 0 :(得分:1)

以下查询集中的每个对象都有一个&#39; filesize_sum&#39;属性包含自该对象的创建时间以来创建的所有缓存资源的文件大小的摘要。

qs = CachedResource.objects.order_by('-created').extra(select={
  'filesize_sum': """
   SELECT
     SUM(filesize)
   FROM
     CachedResource_table_name as cr
   WHERE
     cr.created >= CachedResource_table_name.created
     """})

然后你可以做一个循环来做你想要的。例如,您可以使用filesize_sum&gt;创建一个在第一个对象上打破的循环; 200MB并在查询集上对该对象创建日期较小或相等的所有对象运行删除查询:

for obj in qs:
   if obj.filesize_sum > 200:
       qs.filter(created__lte=obj.created).delete()
       break

请记住,您可能还想在插入新缓存资源之前采取一些操作,以便新资源的文件大小不会超出您的限制。例如,您可以使用以下命令运行上述过程:

limit = configured_limit - filesize_of_cache_resource_to_insert

答案 1 :(得分:0)

可能有更好的方法:

cachedResources = CachedResource.objects.order_by('-created')
list_of_items = []
size_of_files = 0
for item in cachedResources:
    if size_of_files < 200:
        list_of_items.append(item.id)
    else
        break
cached_resources_by_size = CachedResource.objects.filter(id__in=list_of_items).order_by('-created')

答案 2 :(得分:0)

totals = CachedResource.objects.values('id').aggregate(sum=Sum('filesize'), count=Count('id'))
num_to_keep = totals['count'] * min(MAX_FILESIZE / totals['sum'], 1)
while num_to_keep < totals['count']:
    new_sum = CachedResource.objects.filter(id__in=CachedResource.objects.order_by('-created')[:num_to_keep]).aggregate(sum=Sum('filesize'))
    # if <not acceptable approximation>:
    #    adjust approximation
    #    continue

    CachedResource.objects.order_by('-created')[num_to_keep:].delete()
    break

第1行中的聚合可以获得单个查询中的总文件大小和条目数。根据这些结果,可以很容易地计算出要保留的近似条目数量。你可以做一些额外的检查来断言这个近似值在一定限度内(如你所说的+/- 20%)。然后,简单的order_by和切片将生成要删除的所有条目的查询集。