├── 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 |
5 |
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, '