Опрос добавляет несколько голосов

#python #django #django-models #django-views

Вопрос:

Я создаю приложение для опроса, и я застрял на проблеме.

То, что я пытаюсь сделать :-

Я пытаюсь голосовать только за One choice at a time , и если пользователь хочет изменить voting choice , то пользователь также может изменить выбор. НО в это время, когда пользователь выбирает first choice , он добавляет голосование снова и снова, и если пользователь выбирает second option , то оба добавляют ( первый выбор и второй выбор ). НО я пытаюсь добавить только один выбор за раз.

views.py

 def poll_vote(request, poll_id):
    poll = get_object_or_404(Poll, pk=poll_id)
    choice_id = request.POST.get('choice')

    if choice_id:
        choice = Choice.objects.get(id=choice_id)
        vote = Vote(user=request.user, poll=poll, choice=choice)
        vote.save()
        print(vote)
        return render(request, 'polls/poll_result.html', {'poll': poll})
    else:
        messages.error(
            request, "No choice selected")
        return redirect("polls:polls_detail_view", poll_id)
    return render(request, 'polls/poll_result.html', {'poll': poll})
 

Я также попробовал это с poll_vote учетом

     if not poll.user_can_vote(request.user):
        messages.error(request, "You already voted this poll")
        return redirect("polls:polls_detail_view",poll_id=poll_id)
 

Это работает нормально, например :- Когда пользователь голосует first choice , это мешает пользователю выбрать второй вариант, но я хочу, чтобы пользователь мог изменить другой вариант после голосования.

models.py

 
class Poll(models.Model):
    owner = models.ForeignKey(User,null=True,on_delete=models.CASCADE)
    text = models.TextField()
    date = models.DateTimeField(default=timezone.now)

    def user_can_vote(self, user):

        user_votes = user.vote_set.all()
        qs = user_votes.filter(poll=self)
        if qs.exists():
            return False
        return True

class Choice(models.Model):
    poll = models.ForeignKey(Poll,on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=30)


class Vote(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    poll = models.ForeignKey(Poll,on_delete=models.CASCADE)
    choice = models.ForeignKey(Choice,on_delete=models.CASCADE)
 

Я понятия не имею, как заставить пользователя изменить выбор голоса после голосования.

Любая помощь была бы очень признательна.

Заранее спасибо.

Ответ №1:

Вы можете использовать update_or_create [документы Django] для обновления существующего голосования или создания нового:

 def poll_vote(request, poll_id):
    poll = get_object_or_404(Poll, pk=poll_id)
    choice_id = request.POST.get('choice')

    if choice_id:
        choice = Choice.objects.get(id=choice_id)
        vote, created = Vote.objects.update_or_create(
            user=request.user,
            poll=poll,
            defaults={'choice': choice}
        )
        print(vote)
        return render(request, 'polls/poll_result.html', {'poll': poll})
    else:
        messages.error(
            request, "No choice selected")
        return redirect("polls:polls_detail_view", poll_id)
    return render(request, 'polls/poll_result.html', {'poll': poll})
 

Если у вас есть какие-либо дубликаты экземпляров Vote , вам следует сначала удалить их, прежде чем использовать это. Также вам следует добавить UniqueConstraint [документы Django] в свою Vote модель, чтобы предотвратить дубликаты:

 class Vote(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    poll = models.ForeignKey(Poll,on_delete=models.CASCADE)
    choice = models.ForeignKey(Choice,on_delete=models.CASCADE)
    
    class Meta:
        constraints = [
            models.UniqueConstraint(fields=['user', 'poll'], name='unique_user_poll')
        ]
 

Ответ №2:

Нужно проверить, есть ли у этого пользователя существующий голос. Ваш код создает новое голосование каждый раз, когда публикуется форма с выбором.

 choice = Choice.objects.get(id=choice_id)
if existing_vote := Vote.objects.filter(user=request.user, poll=poll).first():
    existing_vote.choice = choice
    existing_vote.save()
else:
    vote = Vote(user=request.user, poll=poll, choice=choice)
    vote.save()
return render(request, 'polls/poll_result.html', {'poll': poll})