14

私の最初の実際の Django プロジェクトを行っており、ガイダンスが必要です。

背景: 私のプロジェクトは reddit クローンです。ユーザーはリンクとテキストを送信します。訪問者は賛成票または反対票を投じます。social_ranking アルゴがあり、バックグラウンド スクリプトとして約 2 分ごとに実行され、正味の投票数とコンテンツの鮮度に応じてすべての投稿を再ランク付けします。かなりバニラのもの。

問題:がではなくとして初期化されているため、 並べ替えがvotes正しく機能しません。これにより、投票のある提出物は、反対票のある提出物よりも低くランク付けされます。この問題を何日もデバッグしましたが、うまくいきませんでした。votesNone0None

詳細: モデルのモデル マネージャーをオーバーライドして、Sum集計関数をクエリ セットに注釈を付け、そのクエリ セットを「社会的ランク」と投票で並べ替えました。

以下は私のmodels.pyです。私は を使用しているDjango 1.5ため、ここに表示されるものは 1.8 に対応していない可能性があります (例get_query_setvs get_queryset):

class LinkVoteCountManager(models.Manager):
    def get_query_set(self):
        return super(LinkVoteCountManager, self).get_query_set().annotate(votes=Sum('vote__value')).order_by('-rank_score', '-votes') 

class Link(models.Model):
    description = models.TextField(_("Write something"))
    submitter = models.ForeignKey(User)
    submitted_on = models.DateTimeField(auto_now_add=True)
    rank_score = models.FloatField(default=0.0)
    url = models.URLField(_("Link"), max_length=250, blank=True)

    with_votes = LinkVoteCountManager() 
    objects = models.Manager() 

    def __unicode__(self): 
        return self.description

    def set_rank(self):
        # Based on reddit ranking algo at http://amix.dk/blog/post/19588
        epoch = datetime(1970, 1, 1).replace(tzinfo=None)
        netvotes = self.votes # 'NONE' votes are messing up netvotes amount.
        if netvotes == None:
            netvotes = 0
        order = log(max(abs(netvotes), 1), 10)
        sign = 1 if netvotes > 0 else -1 if netvotes < 0 else 0
        unaware_submission = self.submitted_on.replace(tzinfo=None)
        td = unaware_submission - epoch 
        epoch_submission = td.days * 86400 + td.seconds + (float(td.microseconds) / 1000000)
        secs = epoch_submission - 1432201843
        self.rank_score = round(sign * order + secs / 45000, 8)
        self.save()

class Vote(models.Model):
    voter = models.ForeignKey(User)
    link = models.ForeignKey(Link)
    value = models.IntegerField(null=True, blank=True, default=0)

    def __unicode__(self):
        return "%s gave %s to %s" % (self.voter.username, self.value, self.link.description)

必要に応じて、以下は私のviews.pyからの関連セクションです。

class LinkListView(ListView):
    model = Link
    queryset = Link.with_votes.all()
    paginate_by = 10

    def get_context_data(self, **kwargs):
        context = super(LinkListView, self).get_context_data(**kwargs)
        if self.request.user.is_authenticated():
            voted = Vote.objects.filter(voter=self.request.user)
            links_in_page = [link.id for link in context["object_list"]]
            voted = voted.filter(link_id__in=links_in_page)
            voted = voted.values_list('link_id', flat=True)
            context["voted"] = voted
        return context

class LinkCreateView(CreateView):
    model = Link
    form_class = LinkForm

    def form_valid(self, form):
        f = form.save(commit=False)
        f.rank_score=0
        f.with_votes = 0
        f.category = '1'
        f.save()
        return super(CreateView, self).form_valid(form)

「 」の問題を修正するために私が何をする必要があるかを誰かが明らかにすることはできますNoneか? 前もって感謝します。

4

2 に答える 2

36

同じ壁にぶつかっただけですが、Noneエントリを結果から除外して無視することにしました。あなたはそれを望んでいないと思います。

ところで、この質問には同じ問題があります。合計に注釈を付けると、ゼロではなくなしになります

その質問の回答で指摘されているように、カスタム sql を使用する以外の解決策については、代わりに Django 1.8 を使用して、Django のバグ トラッカーで 6 年以上開かれているチケットで指摘されている解決策に進むことができます (!) https:// code.djangoproject.com/ticket/10929

Coalesce(Sum('field'), 0)

したがって、あなたのマネージャーは次のようになります。

class LinkVoteCountManager(models.Manager):
    def get_query_set(self):
        return super(LinkVoteCountManager, self).get_query_set().annotate(
            votes=Coalesce(Sum('vote__value'), 0)
        ).order_by(
            '-rank_score', 
            '-votes'
        )

PS: 私は Django 1.8 を自分で使用していないため、コードをテストしていません。

于 2015-10-09T20:43:53.650 に答える