Editable pub_date + docstring / format file with black.py

This commit is contained in:
sosokker 2023-09-10 21:52:46 +07:00
parent 1e084ed11c
commit 356e78a839
7 changed files with 78 additions and 40 deletions

View File

@ -26,15 +26,8 @@ SECRET_KEY = config('SECRET_KEY', default='k2pd1p)zwe0qy0k25=sli+7+n^vd-0h*&6vga
#! SECURITY WARNING: don't run with debug turned on in production!
DEBUG = config('DEBUG', default=False, cast=bool)
LANGUAGE_CODE = 'en-us'
ALLOWED_HOSTS = config('ALLOWED_HOSTS', default='*', cast=Csv())
TIME_ZONE = config('TIME_ZONE', default='UTC', cast=str)
USE_I18N = True
USE_TZ = True
# Application definition
INSTALLED_APPS = [
@ -113,7 +106,7 @@ AUTH_PASSWORD_VALIDATORS = [
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
TIME_ZONE = config('TIME_ZONE', default='UTC', cast=str)
USE_I18N = True
@ -124,6 +117,9 @@ USE_TZ = True
# https://docs.djangoproject.com/en/4.2/howto/static-files/
STATIC_URL = '/static/'
# ! On production -> Configure your web server to serve the files in STATIC_ROOT under the URL STATIC_URL
# * https://docs.djangoproject.com/en/4.2/howto/static-files/deployment/
STATIC_ROOT = BASE_DIR / "assets"
STATICFILES_DIRS = [BASE_DIR]
# Default primary key field type

View File

@ -11,6 +11,7 @@ class ChoiceInline(admin.TabularInline):
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {"fields": ["question_text"]}),
("Published date", {"fields": ["pub_date"], "classes": ["collapse"]}),
("End date", {"fields": ["end_date"], "classes": ["collapse"]}),
("Vote count", {"fields": ["up_vote_count", "down_vote_count"]}),
("Participant count", {"fields": ["participant_count"]}),

View File

@ -0,0 +1,19 @@
# Generated by Django 4.2.4 on 2023-09-09 15:16
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('polls', '0007_question_participant_count'),
]
operations = [
migrations.AlterField(
model_name='question',
name='pub_date',
field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='date published'),
),
]

View File

@ -23,16 +23,32 @@ class Question(models.Model):
Attributes:
question_text (str): The text of the poll question.
pub_date (datetime): The date and time when the question was published.
end_date (datetime): The date and time when the question will end.
long_description (str): The long description of the poll question.
short_description (str): The short description of the poll question.
up_vote_count (int): The number of up votes the question has received.
down_vote_count (int): The number of down votes the question has received.
participant_count (int): The number of participants in the poll.
"""
question_text = models.CharField(max_length=100)
short_description = models.CharField(max_length=200, default="Cool kids have polls")
long_description = models.TextField(max_length=2000, default="No description provide for this poll.")
pub_date = models.DateTimeField("date published", default=timezone.now, editable=False)
long_description = models.TextField(
max_length=2000, default="No description provide for this poll."
)
pub_date = models.DateTimeField(
"date published", default=timezone.now, editable=True
)
end_date = models.DateTimeField("date ended", null=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)])
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):
"""
@ -101,13 +117,13 @@ class Question(models.Model):
time_left_str = ""
if days > 0:
time_left_str += f"{int(days)} D "
time_left_str += f"{int(days)} Days "
elif hours > 0:
time_left_str += f"{int(hours)} H "
time_left_str += f"{int(hours)} Hours "
elif minutes > 0:
time_left_str += f"{int(minutes)} M "
time_left_str += f"{int(minutes)} Mins "
elif seconds > 0:
time_left_str += f"{int(seconds)} S "
time_left_str += f"{int(seconds)} Sec "
return time_left_str.strip()
@ -116,6 +132,7 @@ class Question(models.Model):
return self.calculate_time_left()
def calculate_vote_percentage(self):
"""Calculate the percentage of up votes and down votes."""
total_vote = self.up_vote_count + self.down_vote_count
if total_vote == 0:
return (0, 0)
@ -146,25 +163,32 @@ class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.PositiveIntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(2147483647)])
votes = models.PositiveIntegerField(
default=0, validators=[MinValueValidator(0), MaxValueValidator(2147483647)]
)
def tailwind_width_class(self):
"""
Calculate and return the Tailwind CSS width class based on the 'votes' percentage.
"""
total_votes = self.question.choice_set.aggregate(Sum('votes')).get('votes__sum', 0)
total_votes = self.question.choice_set.aggregate(Sum("votes")).get(
"votes__sum", 0
)
#! Tailwind w-0 to w-48
if total_votes == 0:
return 'w-0'
return "w-0"
ratio = self.votes / total_votes
scaled_value = ratio * 48
return f'w-{int(round(scaled_value))}'
return f"w-{int(round(scaled_value))}"
def calculate_percentage(self):
total_votes_for_question = self.question.choice_set.aggregate(Sum('votes'))['votes__sum'] or 0
"""Calculate percentage of votes for all choices."""
total_votes_for_question = (
self.question.choice_set.aggregate(Sum("votes"))["votes__sum"] or 0
)
if total_votes_for_question == 0:
return 0
@ -176,4 +200,3 @@ class Choice(models.Model):
Returns a string representation of the choice.
"""
return self.choice_text

View File

@ -49,7 +49,7 @@ class QuestionModelTests(TestCase):
Questions with the default pub_date (now) are displayed on the index page.
"""
question = Question.objects.create(question_text="Default pub date question.")
response = self.client.get(reverse("polls:index"))
self.assertQuerySetEqual(
response.context["latest_question_list"],
@ -215,4 +215,3 @@ class QuestionDetailViewTests(TestCase):
url = reverse("polls:detail", args=(past_question.id,))
response = self.client.get(url)
self.assertContains(response, past_question.question_text)

View File

@ -9,4 +9,3 @@ urlpatterns = [
path("<int:pk>/results/", views.ResultsView.as_view(), name="results"),
path("<int:question_id>/vote/", views.vote, name="vote"),
]

View File

@ -16,7 +16,9 @@ class IndexView(generic.ListView):
def get_queryset(self):
"""Return the last five published questions."""
return Question.objects.filter(pub_date__lte=timezone.now()).order_by("-pub_date")[:5]
return Question.objects.filter(pub_date__lte=timezone.now()).order_by(
"-pub_date"
)[:5]
class DetailView(generic.DetailView):
@ -36,18 +38,18 @@ class DetailView(generic.DetailView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
question = self.object
context['question_text'] = question.question_text
context['short_description'] = question.short_description
context['long_description'] = question.long_description
context['pub_date'] = question.pub_date
context['end_date'] = question.end_date
context['up_vote_count'] = question.up_vote_count
context['down_vote_count'] = question.down_vote_count
context['participant_count'] = question.participant_count
context["question_text"] = question.question_text
context["short_description"] = question.short_description
context["long_description"] = question.long_description
context["pub_date"] = question.pub_date
context["end_date"] = question.end_date
context["up_vote_count"] = question.up_vote_count
context["down_vote_count"] = question.down_vote_count
context["participant_count"] = question.participant_count
return context
@ -57,7 +59,7 @@ class ResultsView(generic.DetailView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['question'] = self.object
context["question"] = self.object
return context
def render_to_response(self, context, **response_kwargs):
@ -86,4 +88,3 @@ def vote(request, question_id):
selected_choice.votes += 1
selected_choice.save()
return HttpResponseRedirect(reverse("polls:results", args=(question.id,)))