4

さまざまなハッシュタグのペアを比較できるアプリを書いています。

モデル:

class Competitors(models.Model):
    tag1 = models.ForeignKey('Hashtag', related_name='+')
    tag2 = models.ForeignKey('Hashtag', related_name='+')
    votes = models.PositiveIntegerField(default=0, null=False)

意見:

def compare_hashes(request, i=None):
    i = i or 0
    try:
        competitors = Competitors.objects.order_by('?')[i]
    except IndexError:
        return render(request, 'hash_to_hash.html',
            {'tag1': '', 'tag2': '', i: 0, 'done': True})

    if request.method == 'POST':
        form = CompetitorForm(request.POST)
        if form.is_valid():
            if "yes" in request.POST:
                competitors.votes += 1
                competitors.save()
        i += 1
        return render(request, 'hash_to_hash.html',
                  {'tag1': competitors.tag1, 'tag2': competitors.tag2, i: i, 'done': False})

    else:
        return render(request, 'hash_to_hash.html',
                  {'tag1': competitors.tag1, 'tag2': competitors.tag2, i: i, 'done': False})

私がやりたいことは、訪問者ごとに、競合他社オブジェクトの順序をランダム化し、そのランダム化されたリストを反復処理することです。

質問:

  1. o 以外のものをランダム化するより良い方法は何bjects.order_by('?')ですか? 私は MySQL を使用しており、ここでorder_by('?')+ MySQL = SLOOOOOOOW についていくつか見てきました。いくつかの提案があり、何かを簡単に実装できました (の行に沿って何かを考えていましたrandom.shuffle(Competitors.objects.all())) が、それをどこに置くかわかりません。それが私の 2 番目の質問につながります...
  2. ランダム化が 1 回だけ行われるようにするにはどうすればよいですか? 同じペアを何度もレビューさせて人々を退屈させたくありません。また、いくつかのペアをランダムに複数回表示して結果を台無しにしたくありません。順序を変えて、同じリストをみんなに見てもらいたいです。

答えは Manager クラスにあるのではないかと思いますが、実際には、これはすべて、Django がいつ何を呼び出すかについての知識が不足していることが原因です。

(結果がデータベースに保存されていないように見える問題もありますが、それは別の、おそらくより簡単に解決できる問題です。)

4

3 に答える 3

4

PostgreSQL で Greg の回答を試してみたところ、エラーが発生しました。シードを持つランダム関数がないためです。しばらく考えた後、私は別の方法でその仕事を Python に任せました。

def order_items_randomly(request, items):
    if not request.session.get('random_seed', False):
        request.session['random_seed'] = random.randint(1, 10000)
    seed = request.session['random_seed']
    random.seed(seed)
    items = list(items)
    random.shuffle(items)
    return items

1.5k アイテムのクエリセットで十分に速く動作します。

PSそして、クエリセットをリストに変換しているので、ページネーションの直前にこの関数を実行することをお勧めします。

于 2013-11-28T21:06:35.517 に答える
2

一貫したランダムな順序を維持するには、シードがセッションに保存されている状態で、シードされたランダムで順序付けする必要があります。残念ながら、純粋な django orm ではこれを行うことはできませんが、mysql では簡単です。

import random
from django.conf import settings

# there might be a better way to do this...
DATABASE_ENGINE = settings.DATABASES[settings.DATABASES.keys()[0]]['ENGINE'].split('.')[-1]

def compare_hashes(request, i=None):
    competitors = Competitors.objects.all()

    if DATABASE_ENGINE == 'mysql':
        if not request.session.get('random_seed', False):
            request.session['random_seed'] = random.randint(1, 10000)
        seed = request.session['random_seed']
        competitors = competitors.extra(select={'sort_key': 'RAND(%s)' % seed}).order_by('sort_key')

    # now competitors is randomised but consistent for the session
    ...

ほとんどの状況でパフォーマンスが問題になるとは思えません。あなたの最善の策は、ランダムな値で定期的に更新されるインデックス付きの sort_key 列をデータベースに作成し、セッション用にそれらの 1 つを注文することです。

于 2013-05-17T00:32:28.717 に答える
0

上記のGregのすばらしい提案に主に基づいた私の解決策:

意見:

def compare_hashes(request, i=0):
    i = int(i)
    competitors = Competitors.objects.all()
    DATABASE_ENGINE = settings.DATABASES['default']['ENGINE'].split('.')[-1]
    if DATABASE_ENGINE == 'mysql':
        if not request.session.get('random_seed',False):
            ints = xrange(10000)
            request.session['random_seed'] = sample(ints,1)[0]
        seed = request.session['random_seed']
        competitors = competitors.extra(select={'sort_key': 'RAND({})'.format(seed)})
        randomized_competitors = competitors.order_by('sort_key')
    try:
        chosen_competitor = randomized_competitors[i]
    except IndexError:
        return render(request, 'hash_to_hash.html',
        {'tag1': '', 'tag2': '', i: 0, 'done': True})

    if request.method == 'POST':
        form = CompetitorForm(request.POST)
        if form.is_valid():
            if "yes" in request.POST:
                competitors.votes += 1
                competitors.save()
            i += 1
    return render(request, 'hash_to_hash.html',
              {'tag1': chosen_competitor.tag1, 'tag2': chosen_competitor.tag2, 'action':'/hash/{}'.format(i), 'done': False})

テンプレート ( Django-bootstrap-toolkitを使用し、まだ作業が必要です):

{% extends 'base.html' %}
{% load bootstrap_toolkit %}
{% block title %}Title{% endblock %}
{% block big_title %}Title{% endblock %}
{% block main-content %}
    <h3>Hash-to-Hash</h3>
    {% if done %}
    <div class="row-fluid">
        <div class="span8">
            <h4>You're Done!</h4>
            <p>Thanks so much!</p>
        </div>
    </div>
    {% else %}
        <div class="row-fluid">
            <div class="span6" id="tag1">
                <h4>{{ tag1.text }}</h4>
            </div>
            <div class="span6" id="tag2">
                <h4>{{ tag2.text }}</h4>
            </div>
        <div class="span8">
            <form action="{{ action }}" method="post">
           {% csrf_token %}
           <!-- {{ form|as_bootstrap }} -->
           {% bootstrap_form form layout="vertical" %}
           <div class="form-actions">
               <button type="submit" class="btn btn-success" name="yes">
                   YES, I think these two tags are co-referential
               </button>
               <button type="submit" class="btn btn-danger" name="no">
                   NO, I don't think these two tags are co-referential
               </button>
            </div>
            </form>
        </div>
    </div>
    {% endif %}
{% endblock %}

URLconf は次のようになります。url(r'^hash/(\d*)$', compare_hashes)

再度、感謝します!

于 2013-05-17T01:51:49.267 に答える