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 の 2 つのランクがあります。トレンド トピックのランクは、各 ttc をループして計算されます。

4

2 に答える 2

1

まず、django-debug-toolbarは素晴らしいものですが、それ自体が非常に遅いことに注意してください。ミドルウェアをコメントアウトすると、応答時間が劇的に向上します。これは非常に便利なツールです。誤解しないでください。私はそれを自分で宗教的に使用していますが、重要なのは、有効になっている間は「遅さ」などの主観的なものでサイトをベンチマークすることはできないということです。

第二に、あなたのコードは少し混乱しているので、あなたが何をすべきかを正確に言うのは難しいです。たとえばTrendingTopicCyclerankday_rankフィールドがありますが、投稿されたコードでそれらを使用することはありません。呼び出しget_day_rankは毎回クエリを発行するので、day_rankフィールド自体をフィルタリングするだけで(そのクエリの必要性を排除して)明らかに効率的ですが、これらのフィールドが実際に設定されているかどうか、またはいつ設定されているかは、ここにあるコードからはわかりません。 。

そのままコードに加えることができる小さな改善は、慎重にを使用することselect_relatedです。たとえばttc.tt.get_day_rank(tt_date))、リスト内包表記で実行されるたびに、取得するためのクエリが発行されtt、次にで別のクエリが発行されget_day_rankます。クエリセットに追加.select_related('tt')するだけで、少なくともそのクエリは削除されますtt

また、実際にDjangoが別のクエリを発行するかどうか(そしておそらくより非効率的なクエリ)はわかりませんが、、、、およびを個別にフィルタリングしても意味がありません。つまりyear、完全な日付でフィルタリングするだけです。 :month day

TrendingTopicCycle.objects.distinct('tt__name') \
    .filter(cycle_time=date)
于 2012-07-24T15:05:07.653 に答える
1
if ttcs:
            return sum([ttc.rank for ttc in ttcs])/len(ttcs)
        return 0

これは、db クエリに置き換えることができます。https://docs.djangoproject.com/en/dev/topics/db/aggregation/

何かのようなもの:

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