2014-05-21 63 views
2

我通常不會以最好的方式編寫我的Python代碼,因爲我相對較新,有人要求我更改Django應用程序,因爲代碼看起來不太好。我怎樣才能用較少的冗餘/複製粘貼來寫這個?

這裏是什麼樣子:

@login_required 
def submission_set_rank(request): 

    r1_obj_id = request.GET.get('rank1','') 
    r2_obj_id = request.GET.get('rank2','') 
    r3_obj_id = request.GET.get('rank3','') 
    r4_obj_id = request.GET.get('rank4','') 
    r5_obj_id = request.GET.get('rank5','') 

    #rate the first BallotStats object 
    ballot_1 = BallotStats.objects.get(object_id=r1_obj_id) 
    ballot_2 = BallotStats.objects.get(object_id=r2_obj_id) 
    ballot_3 = BallotStats.objects.get(object_id=r3_obj_id) 
    ballot_4 = BallotStats.objects.get(object_id=r4_obj_id) 
    ballot_5 = BallotStats.objects.get(object_id=r5_obj_id) 

    ballot_1.score += 5 
    ballot_2.score += 4 
    ballot_3.score += 3 
    ballot_4.score += 2 
    ballot_5.score += 1 

    ballot_1.save() 
    ballot_2.save() 
    ballot_3.save() 
    ballot_4.save() 
    ballot_5.save() 

    return HttpResponseRedirect('/submissions/results/film/') 

事實證明,我意識到,我一直在寫我的Python代碼這種方式,有沒有辦法讓它更好看,而不是佔用了21 +代碼行?

+1

循環迴路循環迴路:)一點點'的......在......'不會傷害有點 –

+1

@Carsten不同意 - 這不僅是代碼風格以及它的大小和美感。這也是關於性能。另外,它真的是django特定的。 – alecxe

+0

這應該是一個帶'ModelChoiceField's和'save()'方法的'Form'。 –

回答

6

最大的問題是不是代碼的風格 - 它是你正在10個查詢:5用於獲取對象和5更新它們。使用__in一次

篩選出對象:

@login_required 
def submission_set_rank(request): 
    keys = {'rank1': 5, 'rank2': 4, 'rank3': 3, 'rank4': 2, 'rank5': 1} 
    ranks = [request.GET.get(key,'') for key in keys] 
    for ballot in BallotStats.objects.filter(object_id__in=ranks): 
     ballot.score += keys[ballot.object_id] 
     ballot.save() 

    return HttpResponseRedirect('/submissions/results/film/') 

這將至多使6個查詢:1獲取對象和5更新它們。

此外,您可以使用commit_manually修飾器「標記」視圖(commit_on_success也適用於您)。它應該speed up things significantly

@login_required 
@transaction.commit_manually 
def submission_set_rank(request): 
    keys = {'rank1': 5, 'rank2': 4, 'rank3': 3, 'rank4': 2, 'rank5': 1} 
    ranks = [request.GET.get(key,'') for key in keys] 
    for ballot in BallotStats.objects.filter(object_id__in=ranks): 
     ballot.score += keys[ballot.object_id] 
     ballot.save() 
    transaction.commit() 

    return HttpResponseRedirect('/submissions/results/film/') 

和我有強烈的感覺,你可以在即使一個更新查詢,做到這一點。例如,通過使用connection.cursor()直接與executemany()幫助:

@login_required 
def submission_set_rank(request): 
    keys = {'rank1': 5, 'rank2': 4, 'rank3': 3, 'rank4': 2, 'rank5': 1} 
    ranks = [{'score': request.GET.get(key,''), 'id': key} for key in keys] 

    cursor = connection.cursor() 
    cursor.executemany(""" 
     UPDATE 
      ballot_stats 
     SET 
      score = score + %(score)s 
     WHERE 
      object_id = %(id)s 
    """, ranks) 

    return HttpResponseRedirect('/submissions/results/film/') 

確保字段和表名是正確的。

+0

爲什麼顯示一個'@ transaction.commit_manually'示例,而不是使用更簡單的內置['update()'](https://docs.djangoproject.com/en/dev/ref/models/querysets/ #update),你鏈接的[article](http://voorloopnul.com/blog/doing-bulk-update-and-bulk-create-with-django-orm/)實際上發現更快? 5'.filter()。update()'調用將完成5個查詢。 – pcoronel

+0

@pcoronel因爲它不是一個簡單的更新。這裏取決於'object_id'值爲字段設置了不同的值。讓我知道你是否可以用'update()'寫下來。謝謝。 – alecxe

+0

使用['F()'](https://docs.djangoproject.com/en/dev/ref/models/queries/#f-expressions)表達式:'BallotStats.objects.filter(object_id = request.GET。獲得( '等級-1', ''))。更新(得分= F(「分數」)+ 5)',那些5將照顧它,也不需要字典映射 – pcoronel

6

就你而言,一點循環根本不會傷害。事實上,一般來說,每當你不得不重複兩次以上時,試着讓它成爲一個循環。

n = 5 
for i in range(1, n+1): 
    obj_id = request.GET('rank' + str(i), '') 
    ballot = BallotStats.objects.get(object_id=obj_id) 
    ballot.score += n - i + 1 
    ballot.save() 
1

如果我們談論節約行代碼,你可以在4線通過用.update()更換您的.save()並使用F()表達照顧+=合併成一條線。另外,正如@alecxe所討論的,這會將查詢減少一半。它會是這樣的:

@login_required 
def submission_set_rank(request): 
    BallotStats.objects.filter(object_id=request.GET.get('rank1','')).update(score=‌​F('score') + 5) 
    BallotStats.objects.filter(object_id=request.GET.get('rank2','')).update(score=‌​F('score') + 4) 
    BallotStats.objects.filter(object_id=request.GET.get('rank3','')).update(score=‌​F('score') + 3) 
    BallotStats.objects.filter(object_id=request.GET.get('rank4','')).update(score=‌​F('score') + 2) 
    BallotStats.objects.filter(object_id=request.GET.get('rank5','')).update(score=‌​F('score') + 1) 

    return HttpResponseRedirect('/submissions/results/film/')