diff --git a/polls/__init__.py b/apps/polls/__init__.py
similarity index 100%
rename from polls/__init__.py
rename to apps/polls/__init__.py
diff --git a/polls/admin.py b/apps/polls/admin.py
similarity index 51%
rename from polls/admin.py
rename to apps/polls/admin.py
index 8c38f3f..4cfee41 100644
--- a/polls/admin.py
+++ b/apps/polls/admin.py
@@ -1,3 +1,6 @@
from django.contrib import admin
+from .models import Question
+
# Register your models here.
+admin.site.register(Question)
diff --git a/polls/apps.py b/apps/polls/apps.py
similarity index 73%
rename from polls/apps.py
rename to apps/polls/apps.py
index d0f109e..afeb961 100644
--- a/polls/apps.py
+++ b/apps/polls/apps.py
@@ -2,4 +2,4 @@ from django.apps import AppConfig
class PollsConfig(AppConfig):
- name = 'polls'
+ name = "apps.polls"
diff --git a/apps/polls/migrations/0001_initial.py b/apps/polls/migrations/0001_initial.py
new file mode 100644
index 0000000..bc3d297
--- /dev/null
+++ b/apps/polls/migrations/0001_initial.py
@@ -0,0 +1,32 @@
+# Generated by Django 6.0 on 2025-12-21 22:37
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Question',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('question_text', models.CharField(max_length=200)),
+ ('pub_date', models.DateTimeField(verbose_name='date published')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Choice',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('choice_text', models.CharField(max_length=200)),
+ ('votes', models.IntegerField(default=0)),
+ ('question', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='polls.question')),
+ ],
+ ),
+ ]
diff --git a/polls/migrations/__init__.py b/apps/polls/migrations/__init__.py
similarity index 100%
rename from polls/migrations/__init__.py
rename to apps/polls/migrations/__init__.py
diff --git a/apps/polls/models.py b/apps/polls/models.py
new file mode 100644
index 0000000..d21b59b
--- /dev/null
+++ b/apps/polls/models.py
@@ -0,0 +1,26 @@
+import datetime
+
+from django.db import models
+from django.utils import timezone
+
+# Create your models here.
+
+
+class Question(models.Model):
+ question_text = models.CharField(max_length=200)
+ pub_date = models.DateTimeField("date published")
+
+ def __str__(self):
+ return self.question_text
+
+ def was_published_recently(self):
+ return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
+
+
+class Choice(models.Model):
+ question = models.ForeignKey(Question, on_delete=models.CASCADE)
+ choice_text = models.CharField(max_length=200)
+ votes = models.IntegerField(default=0)
+
+ def __str__(self):
+ return self.choice_text
diff --git a/apps/polls/templates/polls/detail.html b/apps/polls/templates/polls/detail.html
new file mode 100644
index 0000000..f0d89b2
--- /dev/null
+++ b/apps/polls/templates/polls/detail.html
@@ -0,0 +1,14 @@
+
diff --git a/apps/polls/templates/polls/index.html b/apps/polls/templates/polls/index.html
new file mode 100644
index 0000000..cc21d76
--- /dev/null
+++ b/apps/polls/templates/polls/index.html
@@ -0,0 +1,13 @@
+{% if latest_question_list %}
+
+{% else %}
+No polls are available.
+{% endif %}
diff --git a/apps/polls/templates/polls/results.html b/apps/polls/templates/polls/results.html
new file mode 100644
index 0000000..3b2c74f
--- /dev/null
+++ b/apps/polls/templates/polls/results.html
@@ -0,0 +1,9 @@
+{{ question.question_text }}
+
+
+{% for choice in question.choice_set.all %}
+ - {{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}
+{% endfor %}
+
+
+Vote again?
diff --git a/polls/tests.py b/apps/polls/tests.py
similarity index 100%
rename from polls/tests.py
rename to apps/polls/tests.py
diff --git a/apps/polls/urls.py b/apps/polls/urls.py
new file mode 100644
index 0000000..8e7e15e
--- /dev/null
+++ b/apps/polls/urls.py
@@ -0,0 +1,15 @@
+from django.urls import path
+
+from . import views
+
+app_name = "polls"
+urlpatterns = [
+ # ex: /polls/
+ path("", views.index, name="index"),
+ # ex: /polls/5/
+ path("specifics//", views.detail, name="detail"),
+ # ex: /polls/5/results/
+ path("/results/", views.results, name="results"),
+ # ex: /polls/5/vote/
+ path("/vote/", views.vote, name="vote"),
+]
diff --git a/apps/polls/views.py b/apps/polls/views.py
new file mode 100644
index 0000000..b2eba60
--- /dev/null
+++ b/apps/polls/views.py
@@ -0,0 +1,45 @@
+from django.db.models import F
+from django.http import HttpResponse, HttpResponseRedirect
+from django.shortcuts import get_object_or_404, render
+from django.urls import reverse
+
+from .models import Choice, Question
+
+
+def index(request):
+ latest_question_list = Question.objects.order_by("-pub_date")[:5]
+ context = {"latest_question_list": latest_question_list}
+ return render(request, "polls/index.html", context)
+
+
+def detail(request, question_id):
+ question = get_object_or_404(Question, pk=question_id)
+ return render(request, "polls/detail.html", {"question": question})
+
+
+def results(request, question_id):
+ question = get_object_or_404(Question, pk=question_id)
+ return render(request, "polls/results.html", {"question": question})
+
+
+def vote(request, question_id):
+ question = get_object_or_404(Question, pk=question_id)
+ try:
+ selected_choice = question.choice_set.get(pk=request.POST["choice"])
+ except (KeyError, Choice.DoesNotExist):
+ # Redisplay the question voting form.
+ return render(
+ request,
+ "polls/detail.html",
+ {
+ "question": question,
+ "error_message": "You didn't select a choice.",
+ },
+ )
+ else:
+ selected_choice.votes = F("votes") + 1
+ selected_choice.save()
+ # Always return an HttpResponseRedirect after successfully dealing
+ # with POST data. This prevents data from being posted twice if a
+ # user hits the Back button.
+ return HttpResponseRedirect(reverse("polls:results", args=(question.id,)))
diff --git a/django_movies/settings.py b/django_movies/settings.py
index a7fe82d..71ee1cc 100644
--- a/django_movies/settings.py
+++ b/django_movies/settings.py
@@ -20,7 +20,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent
# See https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
-SECRET_KEY = 'django-insecure-yt9sy+oy77u7i3adf2&jno_&%448n5ic&ih9tk#s9ad3gxt$#5'
+SECRET_KEY = "django-insecure-yt9sy+oy77u7i3adf2&jno_&%448n5ic&ih9tk#s9ad3gxt$#5"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
@@ -31,51 +31,52 @@ ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
- 'django.contrib.admin',
- 'django.contrib.auth',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.messages',
- 'django.contrib.staticfiles',
+ "apps.polls.apps.PollsConfig",
+ "django.contrib.admin",
+ "django.contrib.auth",
+ "django.contrib.contenttypes",
+ "django.contrib.sessions",
+ "django.contrib.messages",
+ "django.contrib.staticfiles",
]
MIDDLEWARE = [
- 'django.middleware.security.SecurityMiddleware',
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.middleware.common.CommonMiddleware',
- 'django.middleware.csrf.CsrfViewMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'django.contrib.messages.middleware.MessageMiddleware',
- 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+ "django.middleware.security.SecurityMiddleware",
+ "django.contrib.sessions.middleware.SessionMiddleware",
+ "django.middleware.common.CommonMiddleware",
+ "django.middleware.csrf.CsrfViewMiddleware",
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
+ "django.contrib.messages.middleware.MessageMiddleware",
+ "django.middleware.clickjacking.XFrameOptionsMiddleware",
]
-ROOT_URLCONF = 'django_movies.urls'
+ROOT_URLCONF = "django_movies.urls"
TEMPLATES = [
{
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'DIRS': [],
- 'APP_DIRS': True,
- 'OPTIONS': {
- 'context_processors': [
- 'django.template.context_processors.request',
- 'django.contrib.auth.context_processors.auth',
- 'django.contrib.messages.context_processors.messages',
+ "BACKEND": "django.template.backends.django.DjangoTemplates",
+ "DIRS": [],
+ "APP_DIRS": True,
+ "OPTIONS": {
+ "context_processors": [
+ "django.template.context_processors.request",
+ "django.contrib.auth.context_processors.auth",
+ "django.contrib.messages.context_processors.messages",
],
},
},
]
-WSGI_APPLICATION = 'django_movies.wsgi.application'
+WSGI_APPLICATION = "django_movies.wsgi.application"
# Database
# https://docs.djangoproject.com/en/6.0/ref/settings/#databases
DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.sqlite3',
- 'NAME': BASE_DIR / 'db.sqlite3',
+ "default": {
+ "ENGINE": "django.db.backends.sqlite3",
+ "NAME": BASE_DIR / "db.sqlite3",
}
}
@@ -85,16 +86,16 @@ DATABASES = {
AUTH_PASSWORD_VALIDATORS = [
{
- 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+ "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
- 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+ "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
- 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+ "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
- 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+ "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
@@ -102,9 +103,9 @@ AUTH_PASSWORD_VALIDATORS = [
# Internationalization
# https://docs.djangoproject.com/en/6.0/topics/i18n/
-LANGUAGE_CODE = 'en-us'
+LANGUAGE_CODE = "en-us"
-TIME_ZONE = 'UTC'
+TIME_ZONE = "America/New_York"
USE_I18N = True
@@ -114,4 +115,4 @@ USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/6.0/howto/static-files/
-STATIC_URL = 'static/'
+STATIC_URL = "static/"
diff --git a/django_movies/urls.py b/django_movies/urls.py
index 458b564..1561e07 100644
--- a/django_movies/urls.py
+++ b/django_movies/urls.py
@@ -20,5 +20,5 @@ from django.urls import include, path
urlpatterns = [
path("admin/", admin.site.urls),
- path("polls/", include("polls.urls")),
+ path("polls/", include("apps.polls.urls")),
]
diff --git a/polls/models.py b/polls/models.py
deleted file mode 100644
index 71a8362..0000000
--- a/polls/models.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from django.db import models
-
-# Create your models here.
diff --git a/polls/urls.py b/polls/urls.py
deleted file mode 100644
index 5119061..0000000
--- a/polls/urls.py
+++ /dev/null
@@ -1,7 +0,0 @@
-from django.urls import path
-
-from . import views
-
-urlpatterns = [
- path("", views.index, name="index"),
-]
diff --git a/polls/views.py b/polls/views.py
deleted file mode 100644
index d8959da..0000000
--- a/polls/views.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from django.http import HttpResponse
-
-
-def index(request):
- return HttpResponse("Hello, world. You're at the polls index.")
-
-
-def index2(request):
- return HttpResponse("Hello, world. You're at the polls index #2.")