Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding feature to categorize Polls #41

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions polls/admin.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,31 @@
from django.contrib import admin
from .models import Poll, Choice, Vote

from .models import Poll, Choice, Vote, Category

class ChoiceInline(admin.TabularInline): # or admin.StackedInline for a different layout
model = Choice
extra = 1

@admin.register(Poll)
class PollAdmin(admin.ModelAdmin):
list_display = ["text", "owner", "pub_date", "active", "created_at"]
search_fields = ["text", "owner__username"]
list_filter = ["active", 'created_at', 'pub_date']
list_display = ["text", "owner", "category", "pub_date", "active", "created_at"]
search_fields = ["text", "owner__username", "category__name"]
list_filter = ["active", 'created_at', 'pub_date', 'category']
date_hierarchy = "pub_date"
inlines = [ChoiceInline]


@admin.register(Choice)
class ChoiceAdmin(admin.ModelAdmin):
list_display = ["choice_text", "poll", 'created_at', 'updated_at']
search_fields = ["choice_text", "poll__text"]
autocomplete_fields = ["poll"]


@admin.register(Vote)
class VoteAdmin(admin.ModelAdmin):
list_display = ["choice", "poll", "user", 'created_at']
search_fields = ["choice__choice_text", "poll__text", "user__username"]
autocomplete_fields = ["choice", "poll", "user"]

@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
list_display = ["name", "description"]
search_fields = ["name"]
15 changes: 7 additions & 8 deletions polls/forms.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from django import forms
from .models import Poll, Choice

from .models import Poll, Choice, Category

class PollAddForm(forms.ModelForm):

Expand All @@ -11,25 +10,25 @@ class PollAddForm(forms.ModelForm):

class Meta:
model = Poll
fields = ['text', 'choice1', 'choice2']
fields = ['text', 'category', 'choice1', 'choice2']
widgets = {
'text': forms.Textarea(attrs={'class': 'form-control', 'rows': 5, 'cols': 20}),
'category': forms.Select(attrs={'class': 'form-control'}),
}


class EditPollForm(forms.ModelForm):
class Meta:
model = Poll
fields = ['text', ]
fields = ['text', 'category']
widgets = {
'text': forms.Textarea(attrs={'class': 'form-control', 'rows': 5, 'cols': 20}),
'category': forms.Select(attrs={'class': 'form-control'}),
}


class ChoiceAddForm(forms.ModelForm):
class Meta:
model = Choice
fields = ['choice_text', ]
fields = ['choice_text']
widgets = {
'choice_text': forms.TextInput(attrs={'class': 'form-control', })
'choice_text': forms.TextInput(attrs={'class': 'form-control'}),
}
27 changes: 27 additions & 0 deletions polls/migrations/0003_category_poll_category.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Django 5.0.7 on 2024-07-31 19:17

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('polls', '0002_auto_20231018_1318'),
]

operations = [
migrations.CreateModel(
name='Category',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255)),
('description', models.TextField(blank=True, null=True)),
],
),
migrations.AddField(
model_name='poll',
name='category',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polls', to='polls.category'),
),
]
7 changes: 7 additions & 0 deletions polls/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,16 @@
from django.utils import timezone
import secrets

class Category(models.Model):
name = models.CharField(max_length=255)
description = models.TextField(blank=True, null=True)

def __str__(self):
return self.name

class Poll(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='polls', null=True, blank=True)
text = models.TextField()
pub_date = models.DateTimeField(default=timezone.now)
active = models.BooleanField(default=True)
Expand Down
76 changes: 42 additions & 34 deletions polls/templates/polls/endpoll.html
Original file line number Diff line number Diff line change
@@ -1,43 +1,51 @@
{% extends 'base.html' %}


{% block content %}
<div class="container">
{% if messages %}
<div class="messages">
{% for message in messages %}
<div {% if message.tags %} class="{{ message.tags }}" {% endif %}>{{ message }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endfor %}
</div>
{% else %}
<div class="row">
<div class="col-md-8 offset-sm-2">
<h3 class="mt-3 mb-3 text-center">Result for: {{ poll.text }}</h3>
<!-- progress bar -->
<div class="progress mt-3">

{% for choice in poll.get_result_dict %}
<div class="progress-bar bg-{{ choice.alert_class }}" role="progressbar" style="width: {{ choice.percentage }}%;" aria-valuenow="30" aria-valuemin="0"
aria-valuemax="100"><b>{{ choice.text }}-{{ choice.percentage|floatformat }}%</b></div>
{% endfor %}

</div>
<ul class="list-group">
{% for choice in poll.choice_set.all %}
<li class="list-group-item d-flex justify-content-between align-items-center">
{{ choice.choice_text }}
<span class="badge badge-primary badge-pill">{{ choice.get_vote_count }}</span>
</li>
<div class="row center">
<div class="col-md-6 offset-md-3">
<h2>Edit poll</h2>
{% if messages %}
<div class="messages">
{% for message in messages %}
<div {% if message.tags %} class="{{ message.tags }}" {% endif %}>{{ message }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endfor %}
</ul>
</div>
{% endif %}
<a class="btn btn-primary mt-3" href="{% url 'polls:list' %}" role="button">Back To Polls</a>
<form action="" method="POST">
{% csrf_token %}
{% for field in form %}
<div class="form-group">
{{ field.errors }}
{{ field.label_tag }}
{{ field }}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">Update</button>
<a class="btn btn-danger" href="{% url 'polls:delete_poll' poll.id %}" role="button" onclick="return confirm('Are you sure?')">Delete</a>
<a class="btn btn-warning" href="{% url 'polls:add_choice' poll.id %}" role="button">Add Choice</a>
</form>

<div class="choices">
<h2 class="text-center mt-3">Choices</h2>
<hr>
<ul class="list-group">
{% for choice in poll.choice_set.all %}
<li class="list-group-item">
<a href="{% url 'polls:choice_edit' choice.id %}">
<i class="fas fa-pencil-alt"></i>
</a>&nbsp
{{ choice.choice_text }}
</li>
{% endfor %}
</ul>
</div>

</div>

</div>
</div>
{% endblock content %}
{% endblock %}
12 changes: 7 additions & 5 deletions polls/templates/polls/poll_edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
<div class="col-md-6 offset-md-3">
<h2>Edit poll</h2>
{% if messages %}
{% if messages %}
<div class="messages">
{% for message in messages %}
<div {% if message.tags %} class="{{ message.tags }}" {% endif %}>{{ message }}
Expand All @@ -17,7 +16,6 @@ <h2>Edit poll</h2>
{% endfor %}
</div>
{% endif %}
{% endif %}
<form action="" method="POST">
{% csrf_token %}
{% for field in form %}
Expand All @@ -37,13 +35,17 @@ <h2 class="text-center mt-3">Choices</h2>
<hr>
<ul class="list-group">
{% for choice in poll.choice_set.all %}
<li class="list-group-item"><a href="{% url 'polls:choice_edit' choice.id %}"><i class="fas fa-pencil-alt"></i></a>&nbsp
{{ choice.choice_text }}</li>
<li class="list-group-item">
<a href="{% url 'polls:choice_edit' choice.id %}">
<i class="fas fa-pencil-alt"></i>
</a>&nbsp
{{ choice.choice_text }}
</li>
{% endfor %}
</ul>
</div>

</div>
</div>
</div>
{% endblock %}
{% endblock %}
47 changes: 26 additions & 21 deletions polls/templates/polls/polls_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
<div class="container">
<div class="row">
<div class="col-md-8 offset-sm-2">
<h1 class="text-center mb-5">Welcome to polls List!</h1>
<h1 class="text-center mb-5">Welcome to Polls List!</h1>

{% if messages %}
<div class="messages">
{% for message in messages %}
<div {% if message.tags %} class="{{ message.tags }}" {% endif %}>{{ message }}
<div {% if message.tags %} class="{{ message.tags }}" {% endif %}>
{{ message }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
Expand All @@ -17,28 +19,32 @@ <h1 class="text-center mb-5">Welcome to polls List!</h1>
</div>
{% endif %}

<a class="btn btn-{% if 'name' in request.GET %}warning{% else %}primary{% endif %} mb-3" href="?name=True"
role="button"><i class="fas fa-sort-alpha-down"></i>
Name</a>
<a class="btn btn-{% if 'date' in request.GET %}warning{% else %}primary{% endif %} mb-3" href="?date=True"
role="button"><i class="far fa-clock"></i> Date</a>
<a class="btn btn-{% if 'vote' in request.GET %}warning{% else %}primary{% endif %} mb-3" href="?vote=True"
role="button"><i class="fas fa-poll"></i> Vote</a>
<div class="mb-3">
{% for category in categories %}
<a class="btn btn-{% if category.name == selected_category %}warning{% else %}primary{% endif %} mb-3" href="{% url 'polls:list' %}?category={{ category.name }}&search={{ search_term }}&sort={{ request.GET.sort }}&page=1" role="button">{{ category.name }}</a>
{% endfor %}
</div>

<a class="btn btn-{% if 'name' in request.GET.sort %}warning{% else %}primary{% endif %} mb-3" href="{% url 'polls:list' %}?sort=name&search={{ search_term }}&category={{ selected_category }}&page=1" role="button"><i class="fas fa-sort-alpha-down"></i> Name</a>
<a class="btn btn-{% if 'date' in request.GET.sort %}warning{% else %}primary{% endif %} mb-3" href="{% url 'polls:list' %}?sort=date&search={{ search_term }}&category={{ selected_category }}&page=1" role="button"><i class="far fa-clock"></i> Date</a>
<a class="btn btn-{% if 'vote' in request.GET.sort %}warning{% else %}primary{% endif %} mb-3" href="{% url 'polls:list' %}?sort=vote&search={{ search_term }}&category={{ selected_category }}&page=1" role="button"><i class="fas fa-poll"></i> Vote</a>

<a class="btn btn-primary mb-3 float-right" href="{% url 'polls:add' %}" role="button">Add <i class="fas fa-plus"></i></a>

<form class="form-inline">
<form class="form-inline" method="get" action="{% url 'polls:list' %}">
<div class="form-group mr-sm-2 mb-2">
<input type="search" class="form-control" name="search" placeholder="Search" value={{ search_term }}>
<input type="search" class="form-control" name="search" placeholder="Search" value="{{ search_term }}">
</div>
<input type="hidden" name="category" value="{{ selected_category }}">
<input type="hidden" name="sort" value="{{ request.GET.sort }}">
<button type="submit" class="btn btn-primary mb-2"><i class="fas fa-search"></i></button>
</form>


<ul class="list-group">
{% for poll in polls %}
<li class="list-group-item"><a href="{% url 'polls:detail' poll.id %}">{{ poll.text|truncatewords:5 }}
{% if not poll.active%}
<li class="list-group-item">
<a href="{% url 'polls:detail' poll.id %}">{{ poll.text|truncatewords:5 }}
{% if not poll.active %}
<i class="fas fa-check-circle ml-2"></i>
{% endif %}
</a>
Expand All @@ -51,28 +57,27 @@ <h1 class="text-center mb-5">Welcome to polls List!</h1>
title="Edit Poll"><i class="fas fa-pencil-alt float-right btn btn-primary btn-sm mr-1"></i></a>
{% endif %}
</li>

{% endfor %}
</ul>

{% if polls.paginator.num_pages > 1 %}
<nav class="mt-3">
<ul class="pagination">
{% if polls.has_previous %}
<li class="page-item"><a class="page-link" href="?page=1&{{ params }}">First</a></li>
<li class="page-item"><a class="page-link" href="?page={{ polls.previous_page_number }}&{{ params }}">Previous</a></li>
<li class="page-item"><a class="page-link" href="{% url 'polls:list' %}?page=1&search={{ search_term }}&category={{ selected_category }}&sort={{ request.GET.sort }}">First</a></li>
<li class="page-item"><a class="page-link" href="{% url 'polls:list' %}?page={{ polls.previous_page_number }}&search={{ search_term }}&category={{ selected_category }}&sort={{ request.GET.sort }}">Previous</a></li>
{% endif %}

<li class="page-item active"><a class="page-link" href="">{{ polls.number }}</a></li>

{% if polls.has_next %}
<li class="page-item"><a class="page-link" href="?page={{ polls.next_page_number }}&{{ params }}">Next</a></li>
<li class="page-item"><a class="page-link" href="?page={{ polls.paginator.num_pages }}&{{ params }}">Last</a></li>
<li class="page-item"><a class="page-link" href="{% url 'polls:list' %}?page={{ polls.next_page_number }}&search={{ search_term }}&category={{ selected_category }}&sort={{ request.GET.sort }}">Next</a></li>
<li class="page-item"><a class="page-link" href="{% url 'polls:list' %}?page={{ polls.paginator.num_pages }}&search={{ search_term }}&category={{ selected_category }}&sort={{ request.GET.sort }}">Last</a></li>
{% endif %}
</ul>
</nav>
{% endif %}
</div>
</div>
</div>

{% endblock content %}
{% endblock content %}
4 changes: 2 additions & 2 deletions polls/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
urlpatterns = [
path('list/', views.polls_list, name='list'),
path('list/user/', views.list_by_user, name='list_by_user'),
path('list/category/<str:category_name>/', views.list_by_category, name='list_by_category'), # New endpoint
path('add/', views.polls_add, name='add'),
path('edit/<int:poll_id>/', views.polls_edit, name='edit'),
path('delete/<int:poll_id>/', views.polls_delete, name='delete_poll'),
path('end/<int:poll_id>/', views.end_poll, name='end_poll'),
path('edit/<int:poll_id>/choice/add/', views.add_choice, name='add_choice'),
path('edit/choice/<int:choice_id>/', views.choice_edit, name='choice_edit'),
path('delete/choice/<int:choice_id>/',
views.choice_delete, name='choice_delete'),
path('delete/choice/<int:choice_id>/', views.choice_delete, name='choice_delete'),
path('<int:poll_id>/', views.poll_detail, name='detail'),
path('<int:poll_id>/vote/', views.poll_vote, name='vote'),
path('dashboard/', views.dashboard, name='dashboard'),
Expand Down
Loading