如何用较少的冗余/复制粘贴来编写它?

时间:2014-05-21 13:49:27

标签: python django django-views

我通常不会以最好的方式编写我的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行代码?

3 个答案:

答案 0 :(得分: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 :(得分: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/')

我强烈感觉你甚至可以在一次更新查询中执行此操作。例如,在executemany()的帮助下直接使用connection.cursor()

@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/')

确保字段和表名称正确无误。

答案 2 :(得分:1)

如果我们正在谈论保存代码行,您可以将{4}替换为.update()并使用F()表达式将4行合并为一行照顾.save()。此外,正如@alecxe所讨论的,这会将您的查询减少一半。它看起来像这样:

+=