部署后,Django应用程序变得一团糟。比赛条件?

时间:2019-03-18 09:27:26

标签: django python-3.x nginx web-deployment django-2.1

我写了一个django应用进行测验,它会检查用户的答案并在用户提交答案后立即更新分数。这是执行此操作的相应视图-

current_question_key = 0 #This is a global variable.
def check_answer(request):
    current_user = request.user
    current_team = Team.objects.get(user = current_user)
    current_score = current_team.score

    if request.method == "POST":
        answer = request.POST.get('answer')
        question = Question.objects.get(id = current_question_key)
        if answer == question.answer:
            if question in current_team.questions_answered.all(): #This is required to prevent the score from increasing if the somebody submits a correct answer to the same question more than once
                pass
            else:
                current_team.score = current_score + question.score_increment
                current_team.questions_answered.add(question)
                current_team.save()        
        else:
            # This is required to prevent the score from decreasing if someone has answered it correctly earlier
            if question in current_team.questions_answered.all():
                pass
            else :
                current_team.score = current_score - question.score_increment//negative_marking_factor
                current_team.save()
        return HttpResponse(status=204) #This means that the server has successfully processed the request and is not going to return any data.
    else:
        return HttpResponse("Error404")

从用于将问题发送到前端的视图中更改了current_question_key的值-

def game(request):   
    if request.method == "POST":
        key = request.POST.get('questionKey')
        global current_question_key
        current_question_key = key
        question = Question.objects.get(id = key)
        question_text = question.question_text
        data = {
            'question_text':question_text
        }
        return JsonResponse(data)
    else:
        current_user = request.user
        current_team = Team.objects.get(user = current_user)
        score = current_team.score
        name = current_user.username
        return render(request, 'Base/main.html', {'teamname':name, 'score':score})

在django的开发服务器上进行测试时,即使大约有10个人同时使用它,它也可以正常工作。但是,当我尝试使用nginx(托管在我的笔记本电脑上,有5个同时用户)为它提供服务时,该应用程序完全陷入了麻烦,甚至正确答案也被认为是错误的。

我也尝试过Apache,并且遇到了同样的问题。几乎所有请求都处理不正确。这可能与比赛条件有关吗?究竟会发生什么?

1 个答案:

答案 0 :(得分:0)

You cannot use a global variable like this in Django. A Django application usually runs in multiple server processes which do not share memory. Calling the game view would only set the global variable current_question_key in one of the processes. All other processes would still have old values. As a request can be served by any process, you get more or less random results.

The Django development server uses multi-threading instead of multi-processing. Threads, as opposed to processes, share the same memory, so all request see the same value for current_question_key.

You have to store current_question_key for each user in a way that is accessible to all processes. The most obvious solution would be to store this information in the user's session:

request.session['current_question_key'] = ...

Alternatively, you could store it in the database, e.g. with ForeignKey in a customer user model, or if you want to keep track of games any in a separate table like this:

from django.contrib.auth import get_user_model
from django.db import models

class Game(model.Model)
    user = models.ForeignKey(
        get_user_model(),
        on_delete=models.CASCADE
    )
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True, db_index=True)

You can then get the current game for a user by sorting by creation date:

Game.objects.filter(user=request.user).order_by('-created_at').first()

Depending on how often the current question changes, you could also consider using a key-value like Redis, although that complicates things a bit.