2013-05-16 46 views
4

我正在編寫一個應用程序,允許人們比較不同的hashtags對。隨機化Django查詢集一次,然後遍歷它

型號:

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. 什麼是隨機的事情除了Øbjects.order_by('?')的更好的辦法?我正在使用MySQL,並且我在這裏看到了有關order_by('?') + MySQL = SLOOOOOOOW的一些事情。有幾個建議給出了,我可以很容易地實現一些東西(我正在考慮沿着random.shuffle(Competitors.objects.all())的方向),但我不確定我在哪裏放置它,這導致我到第二個問題...
  2. 我如何確保隨機化只發生一次?我不想讓人們一遍又一遍地重複同一對樂曲,而我不想讓一些樂曲隨機出現一次以上,從而甩掉我的結果。我希望每個人都看到相同的列表,只是按不同的順序。

我懷疑答案在於經理類,但實際上,這一切都歸結爲我對Django何時調用的知識缺乏瞭解。

(我也有一個問題,似乎結果不被保存得到我的分貝,但這是一個不同的,可能更容易解決,問題)。

回答

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列,並用隨機值定期更新,然後爲其中一個列進行排序。

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 %} 

的URL配置看起來像這樣:url(r'^hash/(\d*)$', compare_hashes)

謝謝又來了!

2

嘗試格雷格在PostgreSQL的答案,並得到一個錯誤,因爲沒有隨機函數與種子那裏。經過一番思考,我走了另一條道路,給工作外包給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項目查詢集。

P.S.並且,因爲它將查詢集轉換爲列表,所以最好在分頁之前運行此函數。