我有一个Django项目,包括我们库存的刮刀,每隔几个小时在服务器上作为cronjob运行,以及Django Admin页面 - 我们用它来查看/访问所有项目。
我们有大约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
现在我们遇到了这个问题。
在搜索模型和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()调用访问的信息似乎很浪费。然而,我们的查询显然是如此低效,以至于整个站点在执行时锁定了将近一分钟。有没有人知道我们做错了什么?
根据以下评论,我目前正致力于以下解决方案:
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
答案 0 :(得分:1)
获取查询集时使用注释
from django.db.models import Count
class ScrapingOperationAdmin(admin.ModelAdmin):
...
def get_queryset(self, request):
qs = super().get_queryset(request)
qs.annotate(number_of_ads=Count('searches__ads')
return qs