0

我有以下模型及其方法:

class TrendingTopic(models.Model):

    categories = models.ManyToManyField('Category', through='TTCategory', blank=True, null=True)
    location = models.ForeignKey(Location)


    def get_rank(self, t_date=None):
        if t_date:
            ttcs = self.trendingtopiccycle_set.filter(cycle_time__gt=t_date)
        else:
            ttcs = self.trendingtopiccycle_set.all()
        if ttcs:
            return sum([ttc.rank for ttc in ttcs])/len(ttcs)
        return 0

    def get_day_rank(self,t_date):
        ttcs = self.trendingtopiccycle_set.filter(cycle_time__year=t_date.year,
                                            cycle_time__month=t_date.month,
                                            cycle_time__day=t_date.day)
        sum_rank = sum([ttc.day_rank for ttc in ttcs if ttc.day_rank])
        if sum_rank:
            return sum_rank/len(ttcs)
        return 0 


class TrendingTopicCycle(models.Model):

    tt = models.ForeignKey(TrendingTopic)

    cycle_time = models.DateTimeField(default=datetime.now)
    from_tt_before = models.BooleanField(default=False)
    rank = models.FloatField(default=0.0)
    day_rank = models.FloatField(default=0.0)   

然后我有一些在视图中用于检索所需信息的函数:

  • 显示当天最热门的话题:

    def day_topics(tt_date, limit=10):
    
        tts = [(ttc.tt, ttc.tt.get_day_rank(tt_date)) for ttc in \
            TrendingTopicCycle.objects.distinct('tt__name') \
            .filter(cycle_time__year=tt_date.year,
                    cycle_time__month=tt_date.month,
                    cycle_time__day=tt_date.day)]
        sorted_tts = sorted(tts, key=itemgetter(1), 
                       reverse=True)[:limit]
        return sorted_tts   
    
  • 在确定的时间内显示给定位置(woeid)的最佳趋势主题:

    def hot_topics(woeid=None, limit=10):
    
        CYCLE_LIMIT = datetime.now() + relativedelta(hours=-5)
        TT_CYCLES_LIMIT = datetime.now() + relativedelta(days=-2)
        if woeid:
            tts = [ttc.tt for ttc in \
                    TrendingTopicCycle.objects.filter(tt__location__woeid=woeid) \
                    .distinct('tt__name') \
                    .exclude(cycle_time__lt=CYCLE_LIMIT)]
        else:
            tts = [ttc.tt for ttc in \
                    TrendingTopicCycle.objects.distinct('tt__name') \
                    .exclude(cycle_time__lt=CYCLE_LIMIT)]
    
    
        sorted_tts = sorted(tts, key=lambda tt: tt.get_rank(TT_CYCLES_LIMIT),
                    reverse=True)[:limit]    
        return sorted_tts
    

当前解决方案的问题在于它运行速度非常慢,因为它执行了大量查询(100 次)来检索数据。我正在使用 django 调试工具栏来帮助我测量性能。

显然我做错了什么,我正在寻找解决方案,任何帮助将不胜感激。

编辑:

每个热门话题都有一组热门话题周期(ttc)。每个 ttc 有两个等级:一般等级(等级)和 day_rank。趋势主题排名是通过每个 ttc 循环计算的。

4

2 回答 2

1
if ttcs:
            return sum([ttc.rank for ttc in ttcs])/len(ttcs)
        return 0

这可以用数据库查询代替。https://docs.djangoproject.com/en/dev/topics/db/aggregation/

就像是:

ttcs.Aggregate(Sum('rank'))["sum__rank"]
于 2012-07-24T15:07:42.570 回答
1

首先,请注意 django-debug-toolbar 虽然很棒,但它本身非常慢。如果您注释掉它的中间件,您的响应时间会大大提高。这是一个非常有用的工具,不要误会我的意思。我自己使用它,虔诚地,但关键是你不能在启用它时以“慢”之类的主观因素对你的网站进行基准测试。

其次,你的代码有点混乱,所以很难准确地说出你应该做什么。例如,TrendingTopicCycle有一个rankandday_rank字段,但您从不在发布的代码中使用它们。get_day_rank每次调用都会发出一个查询,因此如果您可以仅对day_rank字段本身进行过滤(消除对该查询的需要),显然会更有效,但我无法从您的代码中判断这些字段是否或何时实际设置.

您可以按原样对代码进行的一个小改进是明智地使用select_related. 例如,每次ttc.tt.get_day_rank(tt_date))在列表推导中运行时,都会发出一个查询来获取tt,然后另一个查询在get_day_rank. 简单地添加.select_related('tt')到您的查询集至少会消除对tt.

另外,我不确定它是否真的导致 Django 发出不同的查询(也许是一个效率更低的查询),但无论如何,单独过滤 、 和 没有意义yearmonth过滤完整日期,即: day

TrendingTopicCycle.objects.distinct('tt__name') \
    .filter(cycle_time=date)
于 2012-07-24T15:05:07.653 回答