user16058388
user16058388

Reputation:

Poll is adding multiple votes

I am building a PollApp and I am stuck on a Problem.

What i am trying to do :-

I am trying to vote only on One choice at a time and if user want to change the voting choice then user can also change the choice. BUT at this time, When user is selecting first choice then it is adding vote again and again and if user is selecting second option then both are adding ( first choice and second choice ). BUT i am trying to add only one choice at a time.

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

I also tried this in poll_vote view

    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)

This is working fine like :- When user is voting first choice then it is preventing user from selecting second choice BUT i want, user can change another option after vote.

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)

I have no idea, How can make user to change vote choice after vote.

Any help would be much Appreciated.

Thank You in Advance.

Upvotes: 2

Views: 112

Answers (2)

Abdul Aziz Barkat
Abdul Aziz Barkat

Reputation: 21802

You can use update_or_create [Django docs] to update an existing vote or create a new one:

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

If you have any duplicate instances of Vote you should delete them first before using this. Also you should add a UniqueConstraint [Django docs] to your Vote model to prevent duplicates:

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')
        ]

Upvotes: 2

Alex Ford
Alex Ford

Reputation: 659

Need to check if that user has an existing vote. Your code is creating a new vote everytime form is posted with a choice.

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

Upvotes: 0

Related Questions