【发布时间】:2018-07-13 10:55:44
【问题描述】:
我有一个 Django 项目,它由我们的库存刮板组成,每隔几个小时在服务器上作为 cronjob 运行,以及 Django 管理页面 - 我们用来查看/访问所有项目。
我们有大约 30 个已编入索引的项目。 因此,每个“抓取操作”由大约 30 个单独的“搜索操作”组成,每个“搜索操作”每次运行得到大约 500 个结果。
现在,这个描述有点混乱,所以我在下面列出了模型。
class ScrapingOperation(models.Model):
date_started = models.DateTimeField(default=timezone.now, editable=True)
date_completed = models.DateTimeField(blank=True, null=True)
completed = models.BooleanField(default=False)
round = models.IntegerField(default=-1)
trusted = models.BooleanField(default=True)
class Search(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE)
date_started = models.DateTimeField(default=timezone.now, editable=True)
date_completed = models.DateTimeField(blank=True, null=True)
completed = models.BooleanField(default=False)
round = models.IntegerField(default=1)
scraping_operation = models.ForeignKey(ScrapingOperation, on_delete=models.CASCADE, related_name='searches')
trusted = models.BooleanField(default=True)
def total_ads(self):
return self.ads.count()
class Ad(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE, related_name='ads')
title = models.CharField(max_length=500)
price = models.DecimalField(max_digits=8, decimal_places=2, null=True)
first_seen = models.DateTimeField(default=timezone.now, editable=True)
last_seen = models.DateTimeField(default=timezone.now, editable=True)
def __str__(self):
return self.title
现在这是我们遇到的问题。
在 Search 模型和 SeachOperation 模型的管理页面上,我们希望看到为该特定对象抓取的广告数量(表示为数字)这对我们的四个搜索者来说效果很好,但是我们对 SearchOperation 的实现有遇到问题
这是我们使用的代码:
class ScrapingOperationAdmin(admin.ModelAdmin):
list_display = ['id', 'completed', 'trusted', 'date_started', 'date_completed', 'number_of_ads']
list_filter = ('completed', 'trusted')
view_on_site = False
inlines = [
SearchInlineAdmin,
]
def number_of_ads(self, instance):
total_ads = 0
for search in instance.searches.all():
total_ads += search.ads.count()
return total_ads
我们遇到的问题是:代码有效并提供了正确的数字,但是,在 +/- 10 ScrapingOperation 之后,我们注意到网站在加载页面时开始变慢。我们现在有多达 60 个 ScrapingOperations,当我们在 Django 管理员中单击 ScrapingOperations 页面时,加载几乎需要一分钟。
有没有更有效的方法来做到这一点?我们考虑将广告总数保存到模型本身,但是将一个字段专用于应该通过简单的 .count() 调用访问的信息似乎很浪费。然而,我们的查询显然效率很低,以至于整个站点在执行时锁定了将近一分钟。有谁知道我们做错了什么?
基于下面的 cmets,我目前正在研究以下解决方案:
def number_of_ads(self, instance):
total_ads = 0
searches = Search.objects.filter(scraping_operation=instance).annotate(Count('ads'))
for search in searches:
total_ads += search.ads__count
return total_ads
【问题讨论】:
-
你可能想要实现这个stackoverflow.com/a/31237071/2894123
标签: django django-admin django-queryset