├── pages ├── __init__.py ├── tests │ ├── __init__.py │ └── test_views.py ├── migrations │ └── __init__.py ├── models.py ├── admin.py ├── views.py ├── urls.py └── apps.py ├── polls ├── __init__.py ├── asgi.py ├── wsgi.py ├── urls.py └── settings.py ├── accounts ├── __init__.py ├── tests │ ├── __init__.py │ ├── test_forms.py │ ├── test_models.py │ └── test_views.py ├── migrations │ ├── __init__.py │ └── 0001_initial.py ├── admin.py ├── apps.py ├── urls.py ├── signals.py ├── models.py ├── forms.py └── views.py ├── pollster ├── __init__.py ├── tests │ ├── __init__.py │ ├── test_forms.py │ ├── test_models.py │ └── test_views.py ├── migrations │ ├── __init__.py │ ├── 0004_vote_choice.py │ ├── 0006_vote_question.py │ ├── 0005_auto_20220604_2325.py │ ├── 0003_auto_20220604_1957.py │ ├── 0002_vote.py │ └── 0001_initial.py ├── apps.py ├── templates │ ├── pages │ │ └── index.html │ ├── partials │ │ └── _navbar.html │ ├── accounts │ │ ├── register.html │ │ ├── login.html │ │ └── profile.html │ ├── polls │ │ ├── detail.html │ │ ├── index.html │ │ └── results.html │ └── base.html ├── urls.py ├── admin.py ├── static │ └── css │ │ └── style.css ├── models.py └── views.py ├── db.sqlite3 ├── .gitignore ├── media ├── default.jpg └── profile_pics │ ├── TheEye.png │ ├── TheEye2.png │ └── TheEye_SRE3GUC.png ├── requirements.txt ├── docker-compose.yml ├── manage.py ├── Dockerfile └── README.md /pages/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /polls/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /accounts/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pages/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pollster/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /accounts/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /accounts/tests/test_forms.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pages/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pollster/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /accounts/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pollster/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-akira/Django-Polls/master/db.sqlite3 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .myvenv 2 | myvenv/ 3 | .env 4 | env/ 5 | __pycache__/ 6 | data/ 7 | data 8 | -------------------------------------------------------------------------------- /pages/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /pages/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /media/default.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-akira/Django-Polls/master/media/default.jpg -------------------------------------------------------------------------------- /media/profile_pics/TheEye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-akira/Django-Polls/master/media/profile_pics/TheEye.png -------------------------------------------------------------------------------- /accounts/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Profile 3 | 4 | admin.site.register(Profile) -------------------------------------------------------------------------------- /media/profile_pics/TheEye2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-akira/Django-Polls/master/media/profile_pics/TheEye2.png -------------------------------------------------------------------------------- /pages/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | def index(request): 4 | return render(request, 'pages/index.html') -------------------------------------------------------------------------------- /media/profile_pics/TheEye_SRE3GUC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-akira/Django-Polls/master/media/profile_pics/TheEye_SRE3GUC.png -------------------------------------------------------------------------------- /pages/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | urlpatterns = [ 5 | path('', views.index, name='index') 6 | ] -------------------------------------------------------------------------------- /pages/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class PagesConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'pages' 7 | -------------------------------------------------------------------------------- /pollster/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class PollsterConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'pollster' 7 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | asgiref==3.5.2 2 | Django==3.2.13 3 | Pillow==9.1.1 4 | pytz==2022.1 5 | sqlparse==0.4.2 6 | typing-extensions==4.2.0 7 | gunicorn==20.1.0 8 | whitenoise==5.3.0 9 | dj-database-url==0.5.0 -------------------------------------------------------------------------------- /accounts/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AccountsConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'accounts' 7 | 8 | def ready(self): 9 | import accounts.signals 10 | -------------------------------------------------------------------------------- /pollster/templates/pages/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 |
5 |

Welcome to Django Polls App

6 |

Start answering our polls

7 | View Polls 8 |
9 | {% endblock %} -------------------------------------------------------------------------------- /pollster/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | app_name = 'pollster' 5 | 6 | urlpatterns = [ 7 | path('', views.index, name='index'), 8 | path('/', views.detail, name='detail'), 9 | path('/results/', views.results, name='results'), 10 | path('/vote/', views.vote, name='vote'), 11 | ] -------------------------------------------------------------------------------- /accounts/urls.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth import views as auth_views 2 | from django.urls import path 3 | from . import views 4 | 5 | app_name = 'accounts' 6 | 7 | urlpatterns = [ 8 | path('profile/', views.profile, name='profile'), 9 | path('register/', views.register, name='register'), 10 | path('login/', views.login_view, name='login'), 11 | path('logout/', views.logout_view, name='logout'), 12 | ] -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | db: 5 | image: postgres 6 | volumes: 7 | - ./data/db:/var/lib/postgresql/data 8 | web: 9 | build: . 10 | command: sh -c "python manage.py makemigrations && python manage.py migrate && python manage.py runserver 0.0.0.0:8000" 11 | container_name: polls 12 | volumes: 13 | - .:/polls 14 | ports: 15 | - "8000:8000" 16 | depends_on: 17 | - db -------------------------------------------------------------------------------- /polls/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for polls project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'polls.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /polls/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for polls 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/3.2/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', 'polls.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /accounts/signals.py: -------------------------------------------------------------------------------- 1 | from django.db.models.signals import post_save 2 | from django.contrib.auth.models import User 3 | from django.dispatch import receiver 4 | from .models import Profile 5 | 6 | @receiver(post_save, sender=User) 7 | def create_profile(sender, instance, created, **kwargs): 8 | if created: 9 | Profile.objects.create(user=instance) 10 | 11 | @receiver(post_save, sender=User) 12 | def save_profile(sender, instance, **kwargs): 13 | instance.profile.save() -------------------------------------------------------------------------------- /polls/urls.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.urls import path, include 3 | from django.conf import settings 4 | from django.conf.urls.static import static 5 | 6 | urlpatterns = [ 7 | path('', include('pages.urls')), 8 | path('admin/', admin.site.urls), 9 | path('polls/', include('pollster.urls')), 10 | path('accounts/', include('accounts.urls')), 11 | ] 12 | 13 | if settings.DEBUG: 14 | urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) -------------------------------------------------------------------------------- /pollster/migrations/0004_vote_choice.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.2.13 on 2022-06-04 21:21 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('pollster', '0003_auto_20220604_1957'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='vote', 16 | name='choice', 17 | field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='pollster.choice'), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /pollster/migrations/0006_vote_question.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.2.13 on 2022-06-04 23:45 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('pollster', '0005_auto_20220604_2325'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='vote', 16 | name='question', 17 | field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='pollster.question'), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /pollster/templates/partials/_navbar.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pollster/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Question, Choice, Vote 3 | 4 | admin.site.site_header = 'Polls Admin' 5 | admin.site.site_title = 'Polls Admin Area' 6 | admin.site.index_title = 'Welcome to Polls Admin Area' 7 | 8 | class ChoiceInline(admin.TabularInline): 9 | model = Choice 10 | extra = 3 11 | 12 | class QuestionAdmin(admin.ModelAdmin): 13 | fieldsets = [ 14 | (None, {'fields': ['question_text']}), 15 | ('Date Information', {'fields': ['pub_date']}), 16 | ] 17 | inlines = [ 18 | ChoiceInline, 19 | ] 20 | 21 | admin.site.register(Question, QuestionAdmin) 22 | admin.site.register(Choice) 23 | admin.site.register(Vote) -------------------------------------------------------------------------------- /pollster/migrations/0005_auto_20220604_2325.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.2.13 on 2022-06-04 23:25 2 | 3 | from django.conf import settings 4 | from django.db import migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 11 | ('pollster', '0004_vote_choice'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterUniqueTogether( 16 | name='vote', 17 | unique_together={('choice', 'user')}, 18 | ), 19 | migrations.RemoveField( 20 | model_name='vote', 21 | name='question', 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /accounts/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.contrib.auth.models import User 3 | from PIL import Image 4 | 5 | class Profile(models.Model): 6 | user = models.OneToOneField(User, on_delete=models.CASCADE) 7 | image = models.ImageField(default='default.jpg', upload_to='profile_pics') 8 | 9 | def __str__(self): 10 | return f'{self.user.username} Profile' 11 | 12 | def save(self, force_insert=False, force_update=False, using=None): 13 | super().save() 14 | img = Image.open(self.image.path) 15 | if img.height > 300 or img.width > 300: 16 | output_size = (300,300) 17 | img.thumbnail(output_size) 18 | img.save(self.image.path) -------------------------------------------------------------------------------- /pollster/templates/accounts/register.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 |

Register

5 |
6 | {% csrf_token %} 7 | 8 | {% for field in form %} 9 |
10 |

{{ field.label }}:
{{ field }}

11 | 12 | {% for error in field.errors %} 13 |
14 | {{ error }} 15 |
16 | {% endfor %} 17 |
18 | {% endfor %} 19 |
20 | 21 |
22 | {% endblock %} -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'polls.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10-alpine 2 | 3 | # set work directory 4 | WORKDIR /polls 5 | 6 | # set environment variables 7 | ENV PYTHONDONTWRITEBYTECODE 1 8 | ENV PYTHONUNBUFFERED 1 9 | ENV DEBUG 0 10 | 11 | # install psycopg2 12 | RUN apk update \ 13 | && apk add --virtual build-essential gcc python3-dev musl-dev \ 14 | && apk add postgresql-dev \ 15 | && pip install psycopg2 16 | 17 | # install dependencies 18 | COPY ./requirements.txt . 19 | RUN pip install -r requirements.txt 20 | 21 | # copy project 22 | COPY . . 23 | 24 | # collect static files 25 | RUN python manage.py collectstatic --noinput 26 | 27 | # add and run as non-root user 28 | RUN adduser -D myuser 29 | USER myuser 30 | 31 | # run gunicorn 32 | CMD gunicorn polls.wsgi:application --bind 0.0.0.0:$PORT -------------------------------------------------------------------------------- /pages/tests/test_views.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | from django.urls import reverse 3 | 4 | class ViewsTestCase(TestCase): 5 | def test_index_loads_properly(self): 6 | response = self.client.get('/') 7 | self.assertEqual(response.status_code, 200) 8 | 9 | def test_url_available_by_name(self): 10 | response = self.client.get(reverse('index')) 11 | self.assertEqual(response.status_code, 200) 12 | 13 | def test_template_index_correct(self): 14 | response = self.client.get(reverse('index')) 15 | self.assertTemplateUsed(response, 'pages/index.html') 16 | 17 | def test_template_content(self): 18 | response = self.client.get(reverse('index')) 19 | self.assertContains(response, '