├── .gitignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── accounts ├── __init__.py ├── admin.py ├── apps.py ├── forms.py ├── migrations │ └── __init__.py ├── models.py ├── templates │ └── accounts │ │ ├── login.html │ │ └── register.html ├── tests.py ├── urls.py └── views.py ├── manage.py ├── pollme ├── __init__.py ├── settings.py ├── urls.py ├── views.py └── wsgi.py ├── polls ├── __init__.py ├── admin.py ├── apps.py ├── forms.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_auto_20231018_1318.py │ └── __init__.py ├── models.py ├── templates │ └── polls │ │ ├── add_choice.html │ │ ├── add_poll.html │ │ ├── endpoll.html │ │ ├── poll_detail.html │ │ ├── poll_edit.html │ │ ├── poll_result.html │ │ └── polls_list.html ├── tests.py ├── urls.py └── views.py ├── requirements.txt ├── seeder.py ├── static ├── css │ └── home_style.css └── img │ └── background.jpg └── templates ├── base.html ├── home.html └── includes └── navbar.html /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.pot 3 | *.pyc 4 | __pycache__/ 5 | local_settings.py 6 | db.sqlite3 7 | media 8 | venv 9 | .vscode -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Mahmudul Alam 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Django-Poll-App 2 | 3 | Django poll app is a full featured polling app. You have to register in this app to show the polls and to vote. If you already voted you can not vote again. Only the owner of a poll can add poll , edit poll, update poll, delete poll , add choice, update choice, delete choice and end a poll. If a poll is ended it can not be voted. Ended poll only shows user the final result of the poll. There is a search option for polls. Also user can filter polls by name, publish date, and by number of voted. Pagination will work even after applying filter. 4 | 5 |

Getting Started

6 |

These instructions will get you a copy of the project up and running on your local machine for development and testing purposes.

7 | 8 |

Prerequisites

9 | python== 3.5 or up and django==2.0 or up 10 | 11 |

Installing

12 |
open terminal and type
13 | git clone https://github.com/devmahmud/Django-poll-app.git

14 | 15 |

or simply download using the url below

16 | https://github.com/devmahmud/Django-poll-app.git
17 | 18 |

To migrate the database open terminal in project directory and type

19 | python manage.py makemigrations
20 | python manage.py migrate 21 | 22 |

To use admin panel you need to create superuser using this command

23 | python manage.py createsuperuser 24 | 25 |

To Create some dummy text data for your app follow the step below:

26 | pip install faker 27 | python manage.py shell 28 | import seeder 29 | seeder.seed_all(30) 30 |

Here 30 is a number of entry. You can use it as your own

31 | 32 |

To run the program in local server use the following command

33 | python manage.py runserver 34 | 35 |

Then go to http://127.0.0.1:8000 in your browser

36 | 37 |

Project snapshot

38 |

Home page

39 |
40 | 41 |
42 | 43 |

Login Page

44 |
45 | 46 |
47 | 48 |

Registration Page

49 |
50 | 51 |
52 | 53 |

Poll List Page

54 |
55 | 56 |
57 | 58 |

Poll Add Page

59 |
60 | 61 |
62 | 63 |

Polling page

64 |
65 | 66 |
67 | 68 |

Poll Result Page

69 |
70 | 71 |
72 | 73 |

Poll Edit Page

74 |
75 | 76 |
77 | 78 |

Choice Update Delete Page

79 |
80 | 81 |
82 | 83 |

Author

84 |
85 | Mahmudul alam
86 | Email: expelmahmud@gmail.com 87 |
88 | 89 |
90 |

========Thank You !!!=========

91 |
92 | -------------------------------------------------------------------------------- /accounts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegenius2/Django-Poll-App/6bae20162173778fae0318541b94094a37126a6e/accounts/__init__.py -------------------------------------------------------------------------------- /accounts/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /accounts/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AccountsConfig(AppConfig): 5 | name = 'accounts' 6 | -------------------------------------------------------------------------------- /accounts/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from django.contrib.auth.models import User 3 | 4 | 5 | class UserRegistrationForm(forms.Form): 6 | username = forms.CharField(label='Username', max_length=100, min_length=5, 7 | widget=forms.TextInput(attrs={'class': 'form-control'})) 8 | email = forms.EmailField(label='Email', max_length=35, min_length=5, 9 | widget=forms.EmailInput(attrs={'class': 'form-control'})) 10 | password1 = forms.CharField(label='Password', max_length=50, min_length=5, 11 | widget=forms.PasswordInput(attrs={'class': 'form-control'})) 12 | password2 = forms.CharField(label='Confirm Password', 13 | max_length=50, min_length=5, 14 | widget=forms.PasswordInput(attrs={'class': 'form-control'})) 15 | -------------------------------------------------------------------------------- /accounts/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegenius2/Django-Poll-App/6bae20162173778fae0318541b94094a37126a6e/accounts/migrations/__init__.py -------------------------------------------------------------------------------- /accounts/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /accounts/templates/accounts/login.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 |
5 |
6 |

Login

7 | {% if messages %} 8 |
9 | {% for message in messages %} 10 |
{{ message }} 11 | 14 |
15 | {% endfor %} 16 |
17 | {% endif %} 18 |
19 | {% csrf_token %} 20 |
21 | 22 | 24 |
25 |
26 | 27 | 29 |
30 |
31 | 32 |
33 |
34 |
35 |

Don't have an account? Sign 37 | Up

38 |
39 |
40 |
41 | {% endblock %} -------------------------------------------------------------------------------- /accounts/templates/accounts/register.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 |
5 |
6 |
7 |

Already have an account? Login Here

8 | {% if messages %} 9 |
10 | {% for message in messages %} 11 |
{{ message }} 12 | 15 |
16 | {% endfor %} 17 |
18 | {% endif %} 19 |
20 | {% csrf_token %} 21 | {{ form.as_p }} 22 | 23 |
24 |
25 |
26 |
27 | {% endblock %} -------------------------------------------------------------------------------- /accounts/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /accounts/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | app_name = "accounts" 5 | 6 | urlpatterns=[ 7 | path('login/', views.login_user, name='login'), 8 | path('logout/', views.logout_user, name='logout'), 9 | path('register/', views.create_user, name='register'), 10 | ] -------------------------------------------------------------------------------- /accounts/views.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth import authenticate, login, logout 2 | from django.shortcuts import render, redirect 3 | from django.contrib.auth.models import User 4 | from .forms import UserRegistrationForm 5 | from django.contrib import messages 6 | from django.http import HttpResponse 7 | 8 | 9 | def login_user(request): 10 | if request.method == 'POST': 11 | username = request.POST.get('username') 12 | password = request.POST.get('password') 13 | user = authenticate(username=username, password=password) 14 | 15 | if user is not None: 16 | login(request, user) 17 | redirect_url = request.GET.get('next', 'home') 18 | return redirect(redirect_url) 19 | else: 20 | messages.error(request, "Username Or Password is incorrect!", 21 | extra_tags='alert alert-warning alert-dismissible fade show') 22 | 23 | return render(request, 'accounts/login.html') 24 | 25 | 26 | def logout_user(request): 27 | logout(request) 28 | return redirect('home') 29 | 30 | 31 | def create_user(request): 32 | if request.method == 'POST': 33 | check1 = False 34 | check2 = False 35 | check3 = False 36 | form = UserRegistrationForm(request.POST) 37 | if form.is_valid(): 38 | username = form.cleaned_data['username'] 39 | password1 = form.cleaned_data['password1'] 40 | password2 = form.cleaned_data['password2'] 41 | email = form.cleaned_data['email'] 42 | 43 | if password1 != password2: 44 | check1 = True 45 | messages.error(request, 'Password did not match!', 46 | extra_tags='alert alert-warning alert-dismissible fade show') 47 | if User.objects.filter(username=username).exists(): 48 | check2 = True 49 | messages.error(request, 'Username already exists!', 50 | extra_tags='alert alert-warning alert-dismissible fade show') 51 | if User.objects.filter(email=email).exists(): 52 | check3 = True 53 | messages.error(request, 'Email already registered!', 54 | extra_tags='alert alert-warning alert-dismissible fade show') 55 | 56 | if check1 or check2 or check3: 57 | messages.error( 58 | request, "Registration Failed!", extra_tags='alert alert-warning alert-dismissible fade show') 59 | return redirect('accounts:register') 60 | else: 61 | user = User.objects.create_user( 62 | username=username, password=password1, email=email) 63 | messages.success( 64 | request, f'Thanks for registering {user.username}.', extra_tags='alert alert-success alert-dismissible fade show') 65 | return redirect('accounts:login') 66 | else: 67 | form = UserRegistrationForm() 68 | return render(request, 'accounts/register.html', {'form': form}) 69 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == '__main__': 6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'pollme.settings') 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /pollme/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegenius2/Django-Poll-App/6bae20162173778fae0318541b94094a37126a6e/pollme/__init__.py -------------------------------------------------------------------------------- /pollme/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for pollme project. 3 | 4 | Generated by 'django-admin startproject' using Django 2.1.5. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.1/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/2.1/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = 'x*za6xf&_80ofdpae!yzq61g9ffikkx9$*iygbl$j7rr4wlf8t' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 34 | 'django.contrib.admin', 35 | 'django.contrib.auth', 36 | 'django.contrib.contenttypes', 37 | 'django.contrib.sessions', 38 | 'django.contrib.messages', 39 | 'django.contrib.staticfiles', 40 | 'polls.apps.PollsConfig', 41 | 'accounts.apps.AccountsConfig', 42 | ] 43 | 44 | MIDDLEWARE = [ 45 | 'django.middleware.security.SecurityMiddleware', 46 | 'django.contrib.sessions.middleware.SessionMiddleware', 47 | 'django.middleware.common.CommonMiddleware', 48 | 'django.middleware.csrf.CsrfViewMiddleware', 49 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 50 | 'django.contrib.messages.middleware.MessageMiddleware', 51 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 52 | ] 53 | 54 | ROOT_URLCONF = 'pollme.urls' 55 | 56 | TEMPLATES = [ 57 | { 58 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 59 | 'DIRS': [os.path.join(BASE_DIR, 'templates')], 60 | 'APP_DIRS': True, 61 | 'OPTIONS': { 62 | 'context_processors': [ 63 | 'django.template.context_processors.debug', 64 | 'django.template.context_processors.request', 65 | 'django.contrib.auth.context_processors.auth', 66 | 'django.contrib.messages.context_processors.messages', 67 | ], 68 | }, 69 | }, 70 | ] 71 | 72 | WSGI_APPLICATION = 'pollme.wsgi.application' 73 | 74 | 75 | # Database 76 | # https://docs.djangoproject.com/en/2.1/ref/settings/#databases 77 | 78 | DATABASES = { 79 | 'default': { 80 | 'ENGINE': 'django.db.backends.sqlite3', 81 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 82 | } 83 | } 84 | 85 | 86 | # Password validation 87 | # https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators 88 | 89 | AUTH_PASSWORD_VALIDATORS = [ 90 | { 91 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 92 | }, 93 | { 94 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 95 | }, 96 | { 97 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 98 | }, 99 | { 100 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 101 | }, 102 | ] 103 | 104 | 105 | # Internationalization 106 | # https://docs.djangoproject.com/en/2.1/topics/i18n/ 107 | 108 | LANGUAGE_CODE = 'en-us' 109 | 110 | TIME_ZONE = 'Asia/Dhaka' 111 | 112 | USE_I18N = True 113 | 114 | USE_L10N = True 115 | 116 | USE_TZ = True 117 | 118 | 119 | # Static files (CSS, JavaScript, Images) 120 | # https://docs.djangoproject.com/en/2.1/howto/static-files/ 121 | 122 | STATIC_URL = '/static/' 123 | STATICFILES_DIRS = [ 124 | os.path.join(BASE_DIR, 'static') 125 | ] 126 | -------------------------------------------------------------------------------- /pollme/urls.py: -------------------------------------------------------------------------------- 1 | """pollme URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/2.1/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import path, include 18 | from . import views 19 | 20 | urlpatterns = [ 21 | path('', views.home, name='home'), 22 | path('admin/', admin.site.urls), 23 | path('accounts/', include('accounts.urls', namespace="accounts")), 24 | path('polls/', include('polls.urls', namespace="polls")), 25 | ] 26 | -------------------------------------------------------------------------------- /pollme/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | 4 | def home(request): 5 | return render(request,'home.html') -------------------------------------------------------------------------------- /pollme/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for pollme project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'pollme.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /polls/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegenius2/Django-Poll-App/6bae20162173778fae0318541b94094a37126a6e/polls/__init__.py -------------------------------------------------------------------------------- /polls/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Poll, Choice, Vote 3 | 4 | 5 | class ChoiceInline(admin.TabularInline): # or admin.StackedInline for a different layout 6 | model = Choice 7 | extra = 1 8 | 9 | @admin.register(Poll) 10 | class PollAdmin(admin.ModelAdmin): 11 | list_display = ["text", "owner", "pub_date", "active", "created_at"] 12 | search_fields = ["text", "owner__username"] 13 | list_filter = ["active", 'created_at', 'pub_date'] 14 | date_hierarchy = "pub_date" 15 | inlines = [ChoiceInline] 16 | 17 | 18 | @admin.register(Choice) 19 | class ChoiceAdmin(admin.ModelAdmin): 20 | list_display = ["choice_text", "poll", 'created_at', 'updated_at'] 21 | search_fields = ["choice_text", "poll__text"] 22 | autocomplete_fields = ["poll"] 23 | 24 | 25 | @admin.register(Vote) 26 | class VoteAdmin(admin.ModelAdmin): 27 | list_display = ["choice", "poll", "user", 'created_at'] 28 | search_fields = ["choice__choice_text", "poll__text", "user__username"] 29 | autocomplete_fields = ["choice", "poll", "user"] 30 | -------------------------------------------------------------------------------- /polls/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class PollsConfig(AppConfig): 5 | name = 'polls' 6 | -------------------------------------------------------------------------------- /polls/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from .models import Poll, Choice 3 | 4 | 5 | class PollAddForm(forms.ModelForm): 6 | 7 | choice1 = forms.CharField(label='Choice 1', max_length=100, min_length=1, 8 | widget=forms.TextInput(attrs={'class': 'form-control'})) 9 | choice2 = forms.CharField(label='Choice 2', max_length=100, min_length=1, 10 | widget=forms.TextInput(attrs={'class': 'form-control'})) 11 | 12 | class Meta: 13 | model = Poll 14 | fields = ['text', 'choice1', 'choice2'] 15 | widgets = { 16 | 'text': forms.Textarea(attrs={'class': 'form-control', 'rows': 5, 'cols': 20}), 17 | } 18 | 19 | 20 | class EditPollForm(forms.ModelForm): 21 | class Meta: 22 | model = Poll 23 | fields = ['text', ] 24 | widgets = { 25 | 'text': forms.Textarea(attrs={'class': 'form-control', 'rows': 5, 'cols': 20}), 26 | } 27 | 28 | 29 | class ChoiceAddForm(forms.ModelForm): 30 | class Meta: 31 | model = Choice 32 | fields = ['choice_text', ] 33 | widgets = { 34 | 'choice_text': forms.TextInput(attrs={'class': 'form-control', }) 35 | } 36 | -------------------------------------------------------------------------------- /polls/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.5 on 2021-01-29 16:38 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | import django.utils.timezone 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | initial = True 12 | 13 | dependencies = [ 14 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 15 | ] 16 | 17 | operations = [ 18 | migrations.CreateModel( 19 | name='Choice', 20 | fields=[ 21 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 22 | ('choice_text', models.CharField(max_length=255)), 23 | ], 24 | ), 25 | migrations.CreateModel( 26 | name='Poll', 27 | fields=[ 28 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 29 | ('text', models.TextField()), 30 | ('pub_date', models.DateTimeField(default=django.utils.timezone.now)), 31 | ('active', models.BooleanField(default=True)), 32 | ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 33 | ], 34 | ), 35 | migrations.CreateModel( 36 | name='Vote', 37 | fields=[ 38 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 39 | ('choice', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='polls.choice')), 40 | ('poll', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='polls.poll')), 41 | ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 42 | ], 43 | ), 44 | migrations.AddField( 45 | model_name='choice', 46 | name='poll', 47 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='polls.poll'), 48 | ), 49 | ] 50 | -------------------------------------------------------------------------------- /polls/migrations/0002_auto_20231018_1318.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.14 on 2023-10-18 07:18 2 | 3 | from django.db import migrations, models 4 | import django.utils.timezone 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('polls', '0001_initial'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='choice', 16 | name='created_at', 17 | field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), 18 | preserve_default=False, 19 | ), 20 | migrations.AddField( 21 | model_name='choice', 22 | name='updated_at', 23 | field=models.DateTimeField(auto_now=True), 24 | ), 25 | migrations.AddField( 26 | model_name='poll', 27 | name='created_at', 28 | field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), 29 | preserve_default=False, 30 | ), 31 | migrations.AddField( 32 | model_name='vote', 33 | name='created_at', 34 | field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), 35 | preserve_default=False, 36 | ), 37 | migrations.AddField( 38 | model_name='vote', 39 | name='updated_at', 40 | field=models.DateTimeField(auto_now=True), 41 | ), 42 | ] 43 | -------------------------------------------------------------------------------- /polls/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegenius2/Django-Poll-App/6bae20162173778fae0318541b94094a37126a6e/polls/migrations/__init__.py -------------------------------------------------------------------------------- /polls/models.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import User 2 | from django.db import models 3 | from django.utils import timezone 4 | import secrets 5 | 6 | 7 | class Poll(models.Model): 8 | owner = models.ForeignKey(User, on_delete=models.CASCADE) 9 | text = models.TextField() 10 | pub_date = models.DateTimeField(default=timezone.now) 11 | active = models.BooleanField(default=True) 12 | created_at = models.DateTimeField(auto_now_add=True) 13 | 14 | def user_can_vote(self, user): 15 | """ 16 | Return False if user already voted 17 | """ 18 | user_votes = user.vote_set.all() 19 | qs = user_votes.filter(poll=self) 20 | if qs.exists(): 21 | return False 22 | return True 23 | 24 | @property 25 | def get_vote_count(self): 26 | return self.vote_set.count() 27 | 28 | def get_result_dict(self): 29 | res = [] 30 | for choice in self.choice_set.all(): 31 | d = {} 32 | alert_class = ['primary', 'secondary', 'success', 33 | 'danger', 'dark', 'warning', 'info'] 34 | 35 | d['alert_class'] = secrets.choice(alert_class) 36 | d['text'] = choice.choice_text 37 | d['num_votes'] = choice.get_vote_count 38 | if not self.get_vote_count: 39 | d['percentage'] = 0 40 | else: 41 | d['percentage'] = (choice.get_vote_count / 42 | self.get_vote_count)*100 43 | 44 | res.append(d) 45 | return res 46 | 47 | def __str__(self): 48 | return self.text 49 | 50 | 51 | class Choice(models.Model): 52 | poll = models.ForeignKey(Poll, on_delete=models.CASCADE) 53 | choice_text = models.CharField(max_length=255) 54 | created_at = models.DateTimeField(auto_now_add=True) 55 | updated_at = models.DateTimeField(auto_now=True) 56 | 57 | @property 58 | def get_vote_count(self): 59 | return self.vote_set.count() 60 | 61 | def __str__(self): 62 | return f"{self.poll.text[:25]} - {self.choice_text[:25]}" 63 | 64 | 65 | class Vote(models.Model): 66 | user = models.ForeignKey(User, on_delete=models.CASCADE) 67 | poll = models.ForeignKey(Poll, on_delete=models.CASCADE) 68 | choice = models.ForeignKey(Choice, on_delete=models.CASCADE) 69 | created_at = models.DateTimeField(auto_now_add=True) 70 | updated_at = models.DateTimeField(auto_now=True) 71 | 72 | def __str__(self): 73 | return f'{self.poll.text[:15]} - {self.choice.choice_text[:15]} - {self.user.username}' 74 | -------------------------------------------------------------------------------- /polls/templates/polls/add_choice.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 |
5 |
6 |
7 | {% if edit_choice %} 8 |

Update choice

9 | {% else %} 10 |

Add new choice

11 | {% endif %} 12 | {% if messages %} 13 |
    14 | {% for message in messages %} 15 |
  • {{ message }}
  • 16 | {% endfor %} 17 |
18 | {% endif %} 19 |
20 | {% csrf_token %} 21 | {% for field in form %} 22 |
23 | {{ field.errors }} 24 | {{ field.label_tag }} 25 | {{ field }} 26 |
27 | {% endfor %} 28 | {% if edit_choice %} 29 | 30 | Delete 31 | {% else %} 32 | 33 | {% endif %} 34 |
35 |
36 |
37 |
38 | {% endblock %} -------------------------------------------------------------------------------- /polls/templates/polls/add_poll.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 |
5 |
6 |
7 |

Create new poll

8 | {% if messages %} 9 |
    10 | {% for message in messages %} 11 |
  • {{ message }}
  • 12 | {% endfor %} 13 |
14 | {% endif %} 15 |
16 | {% csrf_token %} 17 | {% for field in form %} 18 |
19 | {{ field.errors }} 20 | {{ field.label_tag }} 21 | {{ field }} 22 |
23 | {% endfor %} 24 | 25 | Back 26 |
27 |
28 |
29 |
30 | {% endblock %} -------------------------------------------------------------------------------- /polls/templates/polls/endpoll.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | 4 | {% block content %} 5 |
6 | {% if messages %} 7 |
8 | {% for message in messages %} 9 |
{{ message }} 10 | 13 |
14 | {% endfor %} 15 |
16 | {% else %} 17 |
18 |
19 |

Result for: {{ poll.text }}

20 | 21 |
22 | 23 | {% for choice in poll.get_result_dict %} 24 |
{{ choice.text }}-{{ choice.percentage|floatformat }}%
26 | {% endfor %} 27 | 28 |
29 |
    30 | {% for choice in poll.choice_set.all %} 31 |
  • 32 | {{ choice.choice_text }} 33 | {{ choice.get_vote_count }} 34 |
  • 35 | {% endfor %} 36 |
37 | {% endif %} 38 | Back To Polls 39 |
40 | 41 |
42 |
43 | {% endblock content %} -------------------------------------------------------------------------------- /polls/templates/polls/poll_detail.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | 4 | {% block content %} 5 |
6 |

Polls details page

7 | {% if messages %} 8 |
9 | {% for message in messages %} 10 |
{{ message }} 11 | 14 |
15 | {% endfor %} 16 |
17 | {% endif %} 18 |
19 |

{{ poll }}

20 |
21 | {% csrf_token %} 22 | {% for choice in poll.choice_set.all %} 23 | 24 | 25 |
26 | {% endfor %} 27 | 28 | Cancel 29 |
30 | 31 |
32 | 33 | {% endblock content %} -------------------------------------------------------------------------------- /polls/templates/polls/poll_edit.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 |
5 |
6 |
7 |

Edit poll

8 | {% if messages %} 9 | {% if messages %} 10 |
11 | {% for message in messages %} 12 |
{{ message }} 13 | 16 |
17 | {% endfor %} 18 |
19 | {% endif %} 20 | {% endif %} 21 |
22 | {% csrf_token %} 23 | {% for field in form %} 24 |
25 | {{ field.errors }} 26 | {{ field.label_tag }} 27 | {{ field }} 28 |
29 | {% endfor %} 30 | 31 | Delete 32 | Add Choice 33 |
34 | 35 |
36 |

Choices

37 |
38 |
    39 | {% for choice in poll.choice_set.all %} 40 |
  •   41 | {{ choice.choice_text }}
  • 42 | {% endfor %} 43 |
44 |
45 | 46 |
47 |
48 |
49 | {% endblock %} -------------------------------------------------------------------------------- /polls/templates/polls/poll_result.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 |
5 | {% if messages %} 6 |
7 | {% for message in messages %} 8 |
{{ message }} 9 | 12 |
13 | {% endfor %} 14 |
15 | {% else %} 16 |
17 |
18 | {% if poll.active %} 19 |

Result for: {{ poll.text }}

20 | {% else %} 21 |

"{{ poll.text }}" Has Ended Polling!

22 | {% endif %} 23 |

Total: {{ poll.get_vote_count }} votes

24 | 25 |
26 | {% for choice in poll.get_result_dict %} 27 |
29 | {{choice.text|truncatewords:2}}-{{choice.percentage|floatformat}}% 30 |
31 | {% endfor %} 32 | 33 |
34 |
    35 | {% for choice in poll.choice_set.all %} 36 |
  • 37 | {{ choice.choice_text }} 38 | {{ choice.get_vote_count }} 39 |
  • 40 | {% endfor %} 41 |
42 | {% endif %} 43 | Back To Polls 44 |
45 | 46 |
47 |
48 | {% endblock content %} -------------------------------------------------------------------------------- /polls/templates/polls/polls_list.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 |
5 |
6 |
7 |

Welcome to polls List!

8 | {% if messages %} 9 |
10 | {% for message in messages %} 11 |
{{ message }} 12 | 15 |
16 | {% endfor %} 17 |
18 | {% endif %} 19 | 20 | 22 | Name 23 | Date 25 | Vote 27 | 28 | Add 29 | 30 |
31 |
32 | 33 |
34 | 35 |
36 | 37 | 38 | 57 | {% if polls.paginator.num_pages > 1 %} 58 | 73 | {% endif %} 74 |
75 |
76 |
77 | 78 | {% endblock content %} -------------------------------------------------------------------------------- /polls/tests.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth import authenticate 2 | from django.contrib.auth.models import User 3 | from django.test import TestCase 4 | from django.utils import timezone 5 | 6 | from .models import Poll, Vote 7 | 8 | 9 | class PollModelTest(TestCase): 10 | def test_user_can_vote(self): 11 | user = User.objects.create_user('john') 12 | poll = Poll.objects.create(owner=user) 13 | self.assertTrue(poll.user_can_vote(user)) 14 | 15 | choice = poll.choice_set.create(choice_text='pizza') 16 | Vote.objects.create(user=user, poll=poll, choice=choice) 17 | self.assertFalse(poll.user_can_vote(user)) 18 | 19 | 20 | class PollViewTest(TestCase): 21 | def test_home(self): 22 | response = self.client.get('/') 23 | self.assertEqual(response.status_code, 200) 24 | 25 | def test_login(self): 26 | User.objects.create_user(username='john', password='rambo') 27 | response = self.client.post( 28 | '/accounts/login/', {'username': 'john', 'password': 'rambo'} 29 | ) 30 | self.assertRedirects(response, '/') 31 | 32 | def test_register(self): 33 | response = self.client.post( 34 | '/accounts/register/', 35 | { 36 | 'username': 'johny', 37 | 'password1': 'rambo', 38 | 'password2': 'rambo', 39 | 'email': 'johny.rambo@usarmy.gov', 40 | }, 41 | ) 42 | self.assertRedirects(response, '/accounts/login/') 43 | # assert that user got actually created in the backend 44 | self.assertIsNotNone(authenticate(username='johny', password='rambo')) 45 | -------------------------------------------------------------------------------- /polls/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | app_name = "polls" 5 | 6 | urlpatterns = [ 7 | path('list/', views.polls_list, name='list'), 8 | path('list/user/', views.list_by_user, name='list_by_user'), 9 | path('add/', views.polls_add, name='add'), 10 | path('edit//', views.polls_edit, name='edit'), 11 | path('delete//', views.polls_delete, name='delete_poll'), 12 | path('end//', views.end_poll, name='end_poll'), 13 | path('edit//choice/add/', views.add_choice, name='add_choice'), 14 | path('edit/choice//', views.choice_edit, name='choice_edit'), 15 | path('delete/choice//', 16 | views.choice_delete, name='choice_delete'), 17 | path('/', views.poll_detail, name='detail'), 18 | path('/vote/', views.poll_vote, name='vote'), 19 | ] 20 | -------------------------------------------------------------------------------- /polls/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render, get_object_or_404, redirect 2 | from django.contrib.auth.decorators import login_required 3 | from django.core.paginator import Paginator 4 | from django.db.models import Count 5 | from django.contrib import messages 6 | from .models import Poll, Choice, Vote 7 | from .forms import PollAddForm, EditPollForm, ChoiceAddForm 8 | from django.http import HttpResponse 9 | 10 | 11 | @login_required() 12 | def polls_list(request): 13 | all_polls = Poll.objects.all() 14 | search_term = '' 15 | if 'name' in request.GET: 16 | all_polls = all_polls.order_by('text') 17 | 18 | if 'date' in request.GET: 19 | all_polls = all_polls.order_by('pub_date') 20 | 21 | if 'vote' in request.GET: 22 | all_polls = all_polls.annotate(Count('vote')).order_by('vote__count') 23 | 24 | if 'search' in request.GET: 25 | search_term = request.GET['search'] 26 | all_polls = all_polls.filter(text__icontains=search_term) 27 | 28 | paginator = Paginator(all_polls, 6) # Show 6 contacts per page 29 | page = request.GET.get('page') 30 | polls = paginator.get_page(page) 31 | 32 | get_dict_copy = request.GET.copy() 33 | params = get_dict_copy.pop('page', True) and get_dict_copy.urlencode() 34 | 35 | context = { 36 | 'polls': polls, 37 | 'params': params, 38 | 'search_term': search_term, 39 | } 40 | return render(request, 'polls/polls_list.html', context) 41 | 42 | 43 | @login_required() 44 | def list_by_user(request): 45 | all_polls = Poll.objects.filter(owner=request.user) 46 | paginator = Paginator(all_polls, 7) # Show 7 contacts per page 47 | 48 | page = request.GET.get('page') 49 | polls = paginator.get_page(page) 50 | 51 | context = { 52 | 'polls': polls, 53 | } 54 | return render(request, 'polls/polls_list.html', context) 55 | 56 | 57 | @login_required() 58 | def polls_add(request): 59 | if request.user.has_perm('polls.add_poll'): 60 | if request.method == 'POST': 61 | form = PollAddForm(request.POST) 62 | if form.is_valid: 63 | poll = form.save(commit=False) 64 | poll.owner = request.user 65 | poll.save() 66 | Choice( 67 | poll=poll, choice_text=form.cleaned_data['choice1']).save() 68 | Choice( 69 | poll=poll, choice_text=form.cleaned_data['choice2']).save() 70 | 71 | messages.success( 72 | request, "Poll & Choices added successfully.", extra_tags='alert alert-success alert-dismissible fade show') 73 | 74 | return redirect('polls:list') 75 | else: 76 | form = PollAddForm() 77 | context = { 78 | 'form': form, 79 | } 80 | return render(request, 'polls/add_poll.html', context) 81 | else: 82 | return HttpResponse("Sorry but you don't have permission to do that!") 83 | 84 | 85 | @login_required 86 | def polls_edit(request, poll_id): 87 | poll = get_object_or_404(Poll, pk=poll_id) 88 | if request.user != poll.owner: 89 | return redirect('home') 90 | 91 | if request.method == 'POST': 92 | form = EditPollForm(request.POST, instance=poll) 93 | if form.is_valid: 94 | form.save() 95 | messages.success(request, "Poll Updated successfully.", 96 | extra_tags='alert alert-success alert-dismissible fade show') 97 | return redirect("polls:list") 98 | 99 | else: 100 | form = EditPollForm(instance=poll) 101 | 102 | return render(request, "polls/poll_edit.html", {'form': form, 'poll': poll}) 103 | 104 | 105 | @login_required 106 | def polls_delete(request, poll_id): 107 | poll = get_object_or_404(Poll, pk=poll_id) 108 | if request.user != poll.owner: 109 | return redirect('home') 110 | poll.delete() 111 | messages.success(request, "Poll Deleted successfully.", 112 | extra_tags='alert alert-success alert-dismissible fade show') 113 | return redirect("polls:list") 114 | 115 | 116 | @login_required 117 | def add_choice(request, poll_id): 118 | poll = get_object_or_404(Poll, pk=poll_id) 119 | if request.user != poll.owner: 120 | return redirect('home') 121 | 122 | if request.method == 'POST': 123 | form = ChoiceAddForm(request.POST) 124 | if form.is_valid: 125 | new_choice = form.save(commit=False) 126 | new_choice.poll = poll 127 | new_choice.save() 128 | messages.success( 129 | request, "Choice added successfully.", extra_tags='alert alert-success alert-dismissible fade show') 130 | return redirect('polls:edit', poll.id) 131 | else: 132 | form = ChoiceAddForm() 133 | context = { 134 | 'form': form, 135 | } 136 | return render(request, 'polls/add_choice.html', context) 137 | 138 | 139 | @login_required 140 | def choice_edit(request, choice_id): 141 | choice = get_object_or_404(Choice, pk=choice_id) 142 | poll = get_object_or_404(Poll, pk=choice.poll.id) 143 | if request.user != poll.owner: 144 | return redirect('home') 145 | 146 | if request.method == 'POST': 147 | form = ChoiceAddForm(request.POST, instance=choice) 148 | if form.is_valid: 149 | new_choice = form.save(commit=False) 150 | new_choice.poll = poll 151 | new_choice.save() 152 | messages.success( 153 | request, "Choice Updated successfully.", extra_tags='alert alert-success alert-dismissible fade show') 154 | return redirect('polls:edit', poll.id) 155 | else: 156 | form = ChoiceAddForm(instance=choice) 157 | context = { 158 | 'form': form, 159 | 'edit_choice': True, 160 | 'choice': choice, 161 | } 162 | return render(request, 'polls/add_choice.html', context) 163 | 164 | 165 | @login_required 166 | def choice_delete(request, choice_id): 167 | choice = get_object_or_404(Choice, pk=choice_id) 168 | poll = get_object_or_404(Poll, pk=choice.poll.id) 169 | if request.user != poll.owner: 170 | return redirect('home') 171 | choice.delete() 172 | messages.success( 173 | request, "Choice Deleted successfully.", extra_tags='alert alert-success alert-dismissible fade show') 174 | return redirect('polls:edit', poll.id) 175 | 176 | 177 | def poll_detail(request, poll_id): 178 | poll = get_object_or_404(Poll, id=poll_id) 179 | 180 | if not poll.active: 181 | return render(request, 'polls/poll_result.html', {'poll': poll}) 182 | loop_count = poll.choice_set.count() 183 | context = { 184 | 'poll': poll, 185 | 'loop_time': range(0, loop_count), 186 | } 187 | return render(request, 'polls/poll_detail.html', context) 188 | 189 | 190 | @login_required 191 | def poll_vote(request, poll_id): 192 | poll = get_object_or_404(Poll, pk=poll_id) 193 | choice_id = request.POST.get('choice') 194 | if not poll.user_can_vote(request.user): 195 | messages.error( 196 | request, "You already voted this poll!", extra_tags='alert alert-warning alert-dismissible fade show') 197 | return redirect("polls:list") 198 | 199 | if choice_id: 200 | choice = Choice.objects.get(id=choice_id) 201 | vote = Vote(user=request.user, poll=poll, choice=choice) 202 | vote.save() 203 | print(vote) 204 | return render(request, 'polls/poll_result.html', {'poll': poll}) 205 | else: 206 | messages.error( 207 | request, "No choice selected!", extra_tags='alert alert-warning alert-dismissible fade show') 208 | return redirect("polls:detail", poll_id) 209 | return render(request, 'polls/poll_result.html', {'poll': poll}) 210 | 211 | 212 | @login_required 213 | def end_poll(request, poll_id): 214 | poll = get_object_or_404(Poll, pk=poll_id) 215 | if request.user != poll.owner: 216 | return redirect('home') 217 | 218 | if poll.active is True: 219 | poll.active = False 220 | poll.save() 221 | return render(request, 'polls/poll_result.html', {'poll': poll}) 222 | else: 223 | return render(request, 'polls/poll_result.html', {'poll': poll}) 224 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | asgiref==3.3.1 2 | Django==3.1.14 3 | pytz==2020.5 4 | sqlparse==0.4.4 5 | -------------------------------------------------------------------------------- /seeder.py: -------------------------------------------------------------------------------- 1 | from polls.models import Choice, Poll, Vote 2 | from django.contrib.auth.models import User 3 | import datetime 4 | import random 5 | import time 6 | from faker import Faker 7 | fake = Faker() 8 | 9 | 10 | def seed_users(num_entries=10, overwrite=False): 11 | """ 12 | Creates num_entries worth a new users 13 | """ 14 | if overwrite: 15 | print("Overwriting Users") 16 | User.objects.all().delete() 17 | count = 0 18 | for _ in range(num_entries): 19 | first_name = fake.first_name() 20 | last_name = fake.last_name() 21 | u = User.objects.create_user( 22 | first_name=first_name, 23 | last_name=last_name, 24 | email=first_name + "." + last_name + "@fakermail.com", 25 | username=first_name + last_name, 26 | password="password" 27 | ) 28 | count += 1 29 | percent_complete = count / num_entries * 100 30 | print( 31 | "Adding {} new Users: {:.2f}%".format( 32 | num_entries, percent_complete), 33 | end='\r', 34 | flush=True 35 | ) 36 | print() 37 | 38 | 39 | def seed_polls(num_entries=10, choice_min=2, choice_max=5, overwrite=False): 40 | """ 41 | Seeds num_entries poll with random users as owners 42 | Each poll will be seeded with # choices from choice_min to choice_max 43 | """ 44 | if overwrite: 45 | print('Overwriting polls') 46 | Poll.objects.all().delete() 47 | users = list(User.objects.all()) 48 | count = 0 49 | for _ in range(num_entries): 50 | p = Poll( 51 | owner=random.choice(users), 52 | text=fake.paragraph(), 53 | pub_date=datetime.datetime.now() 54 | ) 55 | p.save() 56 | num_choices = random.randrange(choice_min, choice_max + 1) 57 | for _ in range(num_choices): 58 | c = Choice( 59 | poll=p, 60 | choice_text=fake.sentence() 61 | ).save() 62 | count += 1 63 | percent_complete = count / num_entries * 100 64 | print( 65 | "Adding {} new Polls: {:.2f}%".format( 66 | num_entries, percent_complete), 67 | end='\r', 68 | flush=True 69 | ) 70 | print() 71 | 72 | 73 | def seed_votes(): 74 | """ 75 | Creates a new vote on every poll for every user 76 | Voted for choice is selected random. 77 | Deletes all votes prior to adding new ones 78 | """ 79 | Vote.objects.all().delete() 80 | users = User.objects.all() 81 | polls = Poll.objects.all() 82 | count = 0 83 | number_of_new_votes = users.count() * polls.count() 84 | for poll in polls: 85 | choices = list(poll.choice_set.all()) 86 | for user in users: 87 | v = Vote( 88 | user=user, 89 | poll=poll, 90 | choice=random.choice(choices) 91 | ).save() 92 | count += 1 93 | percent_complete = count / number_of_new_votes * 100 94 | print( 95 | "Adding {} new votes: {:.2f}%".format( 96 | number_of_new_votes, percent_complete), 97 | end='\r', 98 | flush=True 99 | ) 100 | print() 101 | 102 | 103 | def seed_all(num_entries=10, overwrite=False): 104 | """ 105 | Runs all seeder functions. Passes value of overwrite to all 106 | seeder function calls. 107 | """ 108 | start_time = time.time() 109 | # run seeds 110 | seed_users(num_entries=num_entries, overwrite=overwrite) 111 | seed_polls(num_entries=num_entries, overwrite=overwrite) 112 | seed_votes() 113 | # get time 114 | elapsed_time = time.time() - start_time 115 | minutes = int(elapsed_time // 60) 116 | seconds = int(elapsed_time % 60) 117 | print("Script Execution took: {} minutes {} seconds".format(minutes, seconds)) 118 | -------------------------------------------------------------------------------- /static/css/home_style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | height:100%; 3 | padding: 0; 4 | margin: 0; 5 | color: white; 6 | } 7 | html{ 8 | background-image: url('../img/background.jpg'); 9 | background-size: cover; 10 | } 11 | body { 12 | background: rgba(0, 0, 0, 0.466); 13 | } 14 | #home-content{ 15 | text-align: center; 16 | padding-top: 20%; 17 | } -------------------------------------------------------------------------------- /static/img/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegenius2/Django-Poll-App/6bae20162173778fae0318541b94094a37126a6e/static/img/background.jpg -------------------------------------------------------------------------------- /templates/base.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Poll Me | Polls List 10 | 12 | 14 | 15 | {% block custom_css %}{% endblock custom_css %} 16 | 17 | 18 | 19 | 20 | {% include 'includes/navbar.html' %} 21 | 22 | {% block content %} 23 | 24 | {% endblock content %} 25 | 26 | 27 | 28 | 30 | 32 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /templates/home.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load static %} 3 | {% block custom_css %} 4 | 5 | {% endblock custom_css %} 6 | 7 | 8 | {% block content %} 9 |
10 |
11 |
12 |
13 |

PollMe - Get Started!

14 |

Your Voice Matters!

15 |
16 | Get Started ! 17 |
18 |
19 |
20 |
21 | {% endblock content %} -------------------------------------------------------------------------------- /templates/includes/navbar.html: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------