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! #! SECURITY WARNING: don't run with debug turned on in production!
DEBUG = config('DEBUG', default=False, cast=bool) DEBUG = config('DEBUG', default=False, cast=bool)
LANGUAGE_CODE = 'en-us'
ALLOWED_HOSTS = config('ALLOWED_HOSTS', default='*', cast=Csv()) 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 # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [
@ -113,7 +106,7 @@ AUTH_PASSWORD_VALIDATORS = [
LANGUAGE_CODE = 'en-us' LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC' TIME_ZONE = config('TIME_ZONE', default='UTC', cast=str)
USE_I18N = True USE_I18N = True
@ -124,6 +117,9 @@ USE_TZ = True
# https://docs.djangoproject.com/en/4.2/howto/static-files/ # https://docs.djangoproject.com/en/4.2/howto/static-files/
STATIC_URL = '/static/' 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] STATICFILES_DIRS = [BASE_DIR]
# Default primary key field type # Default primary key field type

View File

@ -11,6 +11,7 @@ class ChoiceInline(admin.TabularInline):
class QuestionAdmin(admin.ModelAdmin): class QuestionAdmin(admin.ModelAdmin):
fieldsets = [ fieldsets = [
(None, {"fields": ["question_text"]}), (None, {"fields": ["question_text"]}),
("Published date", {"fields": ["pub_date"], "classes": ["collapse"]}),
("End date", {"fields": ["end_date"], "classes": ["collapse"]}), ("End date", {"fields": ["end_date"], "classes": ["collapse"]}),
("Vote count", {"fields": ["up_vote_count", "down_vote_count"]}), ("Vote count", {"fields": ["up_vote_count", "down_vote_count"]}),
("Participant count", {"fields": ["participant_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: Attributes:
question_text (str): The text of the poll question. question_text (str): The text of the poll question.
pub_date (datetime): The date and time when the question was published. 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) question_text = models.CharField(max_length=100)
short_description = models.CharField(max_length=200, default="Cool kids have polls") 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.") long_description = models.TextField(
pub_date = models.DateTimeField("date published", default=timezone.now, editable=False) 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) end_date = models.DateTimeField("date ended", null=True)
up_vote_count = models.PositiveIntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(2147483647)]) up_vote_count = models.PositiveIntegerField(
down_vote_count = models.PositiveIntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(2147483647)]) default=0, validators=[MinValueValidator(0), MaxValueValidator(2147483647)]
participant_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): def was_published_recently(self):
""" """
@ -101,13 +117,13 @@ class Question(models.Model):
time_left_str = "" time_left_str = ""
if days > 0: if days > 0:
time_left_str += f"{int(days)} D " time_left_str += f"{int(days)} Days "
elif hours > 0: elif hours > 0:
time_left_str += f"{int(hours)} H " time_left_str += f"{int(hours)} Hours "
elif minutes > 0: elif minutes > 0:
time_left_str += f"{int(minutes)} M " time_left_str += f"{int(minutes)} Mins "
elif seconds > 0: elif seconds > 0:
time_left_str += f"{int(seconds)} S " time_left_str += f"{int(seconds)} Sec "
return time_left_str.strip() return time_left_str.strip()
@ -116,6 +132,7 @@ class Question(models.Model):
return self.calculate_time_left() return self.calculate_time_left()
def calculate_vote_percentage(self): def calculate_vote_percentage(self):
"""Calculate the percentage of up votes and down votes."""
total_vote = self.up_vote_count + self.down_vote_count total_vote = self.up_vote_count + self.down_vote_count
if total_vote == 0: if total_vote == 0:
return (0, 0) return (0, 0)
@ -146,25 +163,32 @@ class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE) question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200) 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): def tailwind_width_class(self):
""" """
Calculate and return the Tailwind CSS width class based on the 'votes' percentage. 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 #! Tailwind w-0 to w-48
if total_votes == 0: if total_votes == 0:
return 'w-0' return "w-0"
ratio = self.votes / total_votes ratio = self.votes / total_votes
scaled_value = ratio * 48 scaled_value = ratio * 48
return f'w-{int(round(scaled_value))}' return f"w-{int(round(scaled_value))}"
def calculate_percentage(self): 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: if total_votes_for_question == 0:
return 0 return 0
@ -176,4 +200,3 @@ class Choice(models.Model):
Returns a string representation of the choice. Returns a string representation of the choice.
""" """
return self.choice_text 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. Questions with the default pub_date (now) are displayed on the index page.
""" """
question = Question.objects.create(question_text="Default pub date question.") question = Question.objects.create(question_text="Default pub date question.")
response = self.client.get(reverse("polls:index")) response = self.client.get(reverse("polls:index"))
self.assertQuerySetEqual( self.assertQuerySetEqual(
response.context["latest_question_list"], response.context["latest_question_list"],
@ -215,4 +215,3 @@ class QuestionDetailViewTests(TestCase):
url = reverse("polls:detail", args=(past_question.id,)) url = reverse("polls:detail", args=(past_question.id,))
response = self.client.get(url) response = self.client.get(url)
self.assertContains(response, past_question.question_text) 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:pk>/results/", views.ResultsView.as_view(), name="results"),
path("<int:question_id>/vote/", views.vote, name="vote"), path("<int:question_id>/vote/", views.vote, name="vote"),
] ]

View File

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