Reputation:
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
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
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