Add up/down Vote + Update admin field

This commit is contained in:
sosokker 2023-09-15 02:22:06 +07:00
parent c3b5984e33
commit f6d0239ec6
7 changed files with 193 additions and 26 deletions

View File

@ -8,9 +8,6 @@
"end_date": "2023-09-29T20:31:49Z",
"short_description": "Cool kids have polls",
"long_description": "No description provide for this poll.",
"up_vote_count": 5,
"down_vote_count": 0,
"participant_count": 6,
"tags": []
}
},
@ -23,9 +20,6 @@
"end_date": "2023-10-18T23:50:19Z",
"short_description": "Cool kids have polls",
"long_description": "No description provide for this poll.",
"up_vote_count": 1,
"down_vote_count": 0,
"participant_count": 0,
"tags": []
}
},
@ -38,9 +32,6 @@
"end_date": "2023-11-28T19:50:53Z",
"short_description": "Cool kids have polls",
"long_description": "No description provide for this poll.",
"up_vote_count": 1,
"down_vote_count": 0,
"participant_count": 0,
"tags": []
}
},
@ -53,9 +44,6 @@
"end_date": "2023-09-29T17:51:18Z",
"short_description": "Cool kids have polls",
"long_description": "No description provide for this poll.",
"up_vote_count": 10,
"down_vote_count": 0,
"participant_count": 0,
"tags": []
}
},
@ -144,7 +132,7 @@
"model": "polls.vote",
"pk": 2,
"fields": {
"choice": 2,
"choice": 1,
"user": 3,
"question": 1
}
@ -153,7 +141,7 @@
"model": "polls.vote",
"pk": 3,
"fields": {
"choice": 1,
"choice": 2,
"user": 2,
"question": 1
}
@ -248,6 +236,24 @@
"question": 3
}
},
{
"model": "polls.vote",
"pk": 14,
"fields": {
"choice": 7,
"user": 3,
"question": 4
}
},
{
"model": "polls.vote",
"pk": 15,
"fields": {
"choice": 2,
"user": 6,
"question": 1
}
},
{
"model": "polls.sentimentvote",
"pk": 1,
@ -256,5 +262,104 @@
"question": 1,
"vote_types": false
}
},
{
"model": "polls.sentimentvote",
"pk": 2,
"fields": {
"user": 2,
"question": 2,
"vote_types": true
}
},
{
"model": "polls.sentimentvote",
"pk": 3,
"fields": {
"user": 2,
"question": 4,
"vote_types": true
}
},
{
"model": "polls.sentimentvote",
"pk": 4,
"fields": {
"user": 2,
"question": 3,
"vote_types": false
}
},
{
"model": "polls.sentimentvote",
"pk": 5,
"fields": {
"user": 2,
"question": 1,
"vote_types": false
}
},
{
"model": "polls.sentimentvote",
"pk": 6,
"fields": {
"user": 6,
"question": 1,
"vote_types": true
}
},
{
"model": "polls.sentimentvote",
"pk": 7,
"fields": {
"user": 6,
"question": 3,
"vote_types": true
}
},
{
"model": "polls.sentimentvote",
"pk": 8,
"fields": {
"user": 6,
"question": 4,
"vote_types": true
}
},
{
"model": "polls.sentimentvote",
"pk": 9,
"fields": {
"user": 3,
"question": 1,
"vote_types": false
}
},
{
"model": "polls.sentimentvote",
"pk": 10,
"fields": {
"user": 3,
"question": 3,
"vote_types": true
}
},
{
"model": "polls.sentimentvote",
"pk": 11,
"fields": {
"user": 3,
"question": 4,
"vote_types": false
}
},
{
"model": "polls.sentimentvote",
"pk": 12,
"fields": {
"user": 3,
"question": 2,
"vote_types": true
}
}
]

View File

@ -13,11 +13,10 @@ class QuestionAdmin(admin.ModelAdmin):
(None, {"fields": ["question_text"]}),
("Published date", {"fields": ["pub_date"], "classes": ["collapse"]}),
("End date", {"fields": ["end_date"], "classes": ["collapse"]}),
("Sentiment Vote count", {"fields": ["up_vote_count", "down_vote_count"]}),
]
list_display = ["question_text", "pub_date", "end_date", "was_published_recently", "can_vote"]
inlines = [ChoiceInline]
list_filter = ["pub_date", ]
list_filter = ["pub_date", "end_date"]
search_fields = ["question_text"]

View File

@ -0,0 +1,25 @@
# Generated by Django 4.2.4 on 2023-09-14 19:15
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('polls', '0013_alter_vote_question'),
]
operations = [
migrations.RemoveField(
model_name='question',
name='down_vote_count',
),
migrations.RemoveField(
model_name='question',
name='participant_count',
),
migrations.RemoveField(
model_name='question',
name='up_vote_count',
),
]

View File

@ -12,7 +12,6 @@ Attributes:
from django.db import models, IntegrityError
from django.utils import timezone
from django.contrib import admin
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db.models import Sum
from django.contrib.auth.models import User
@ -49,10 +48,6 @@ class Question(models.Model):
long_description = models.TextField(max_length=2000, default="No description provide for this poll.")
tags = models.ManyToManyField(Tag, blank=True)
up_vote_count = models.PositiveIntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(2147483647)])
down_vote_count = models.PositiveIntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(2147483647)])
participant_count = models.PositiveIntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(2147483647)])
def was_published_recently(self):
"""
Checks if the question was published recently or not.
@ -164,7 +159,6 @@ class Question(models.Model):
def upvote(self, user):
try:
self.sentimentvote_set.create(user=user, question=self, vote_types=True)
self.up_vote_count += 1
self.save()
except IntegrityError:
vote = self.sentimentvote_set.filter(user=user)
@ -175,11 +169,9 @@ class Question(models.Model):
return False
return True
def downvote(self, user):
try:
self.sentimentvote_set.create(user=user, question=self, vote_types=False)
self.up_vote_count += 1
self.save()
except IntegrityError:
vote = self.sentimentvote_set.filter(user=user)
@ -190,6 +182,14 @@ class Question(models.Model):
return False
return True
@property
def up_vote_count(self):
return self.sentimentvote_set.filter(question=self, vote_types=True).count()
@property
def down_vote_count(self):
return self.sentimentvote_set.filter(question=self, vote_types=False).count()
class Choice(models.Model):
"""

View File

@ -11,6 +11,16 @@
<div class="flex flex-wrap items-center space-x-2">
<header class="flex items-center justify-center">
<div class="flex flex-wrap items-center space-x-2">
<form method="post" action="{% url "polls:upvote" question.id %}">
{% csrf_token %}
<button class="flex items-center whitespace-nowrap rounded-full border-black border-2 border-solid bg-neutral-200 px-5 py-2 text-sm font-bold text-black transition duration-150 ease-in-out hover:scale-[101%] hover:bg-green-500 focus:bg-orange-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 active:bg-orange-900"
type="submit" {% if user_voted == 'upvote' %}disabled{% endif %}>Upvote👍</button>
</form>
<form method="post" action="{% url "polls:downvote" question.id %}">
{% csrf_token %}
<button class="flex items-center whitespace-nowrap rounded-full border-black border-2 border-solid bg-neutral-200 px-5 py-2 text-sm font-bold text-black transition duration-150 ease-in-out hover:scale-[101%] hover:bg-yellow-500 focus:bg-orange-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 active:bg-orange-900"
type="submit" {% if user_voted == 'downvote' %}disabled{% endif %}>Downvote👎</button>
</form>
<!--End-->
<button
onclick="window.location.href='{% url 'polls:index' %}'"

View File

@ -9,4 +9,6 @@ urlpatterns = [
path("<int:pk>/results/", views.ResultsView.as_view(), name="results"),
path("<int:question_id>/vote/", views.vote, name="vote"),
path("signup/", views.SignUpView.as_view(), name="signup"),
path("upvote/<int:question_id>", views.up_down_vote, {'vote_type' : 'upvote'}, name="upvote"),
path("downvote/<int:question_id>", views.up_down_vote, {'vote_type' : 'downvote'}, name="downvote"),
]

View File

@ -1,4 +1,5 @@
import logging
from typing import Any
from django.shortcuts import get_object_or_404, render, redirect
from django.urls import reverse
@ -86,9 +87,18 @@ class ResultsView(LoginRequiredMixin, generic.DetailView):
model = Question
template_name = "polls/results.html"
def render_to_response(self, context, **response_kwargs):
return render(self.request, self.template_name, context)
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
context = super().get_context_data(**kwargs)
user_voted = None
question = self.get_object()
if question.sentimentvote_set.filter(user=self.request.user, question=question, vote_types=True).exists():
user_voted = 'upvote'
elif question.sentimentvote_set.filter(user=self.request.user, question=question, vote_types=False).exists():
user_voted = 'downvote'
context['user_voted'] = user_voted
return context
class SignUpView(generic.CreateView):
form_class = SignUpForm
@ -139,6 +149,22 @@ def vote(request, question_id):
return redirect("polls:index")
@login_required
def up_down_vote(request, question_id, vote_type):
ip = get_client_ip(request)
question = get_object_or_404(Question, pk=question_id)
if request.method == "POST":
if vote_type == "upvote":
if question.upvote(request.user):
messages.success(request, "You upvoted this Poll😊")
elif vote_type == "downvote":
if question.downvote(request.user):
messages.success(request, "You downvoted this Poll😭")
return redirect(reverse("polls:results", args=(question_id,)))
# https://stackoverflow.com/questions/4581789/how-do-i-get-user-ip-address-in-django
def get_client_ip(request):
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')