Add poll app from official tutorial

This commit is contained in:
Lucas Schumacher 2024-05-21 00:47:26 -04:00
parent 5f2bc11155
commit fc89f4e429
16 changed files with 826 additions and 0 deletions

View File

@ -31,6 +31,7 @@ ALLOWED_HOSTS = []
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [
'polls.apps.PollsConfig',
'testapp.apps.TestappConfig', 'testapp.apps.TestappConfig',
'django.contrib.admin', 'django.contrib.admin',
'django.contrib.auth', 'django.contrib.auth',

View File

@ -20,6 +20,7 @@ from django.urls import include, path
urlpatterns = [ urlpatterns = [
# Add the path that our testapp should be served at # Add the path that our testapp should be served at
path("", include("testapp.urls")), path("", include("testapp.urls")),
path('polls/', include('polls.urls')),
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
] ]

0
polls/__init__.py Normal file
View File

6
polls/admin.py Normal file
View File

@ -0,0 +1,6 @@
from django.contrib import admin
from . import models
# Register your models here.
admin.site.register(models.Question)
admin.site.register(models.Choice)

6
polls/apps.py Normal file
View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class PollsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'polls'

View File

@ -0,0 +1,32 @@
# Generated by Django 4.2.11 on 2024-05-20 03:56
from django.db import migrations, models
import django.db.models.deletion
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')),
],
),
]

View File

18
polls/models.py Normal file
View File

@ -0,0 +1,18 @@
from django.db import models
# 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

View File

@ -0,0 +1,386 @@
<!doctype html>
<html lang="en" data-bs-theme="auto">
<head><script src="https://getbootstrap.com/docs/5.3/assets/js/color-modes.js"></script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
<meta name="generator" content="Hugo 0.122.0">
<title>List groups · Bootstrap v5.3</title>
<link rel="canonical" href="https://getbootstrap.com/docs/5.3/examples/list-groups/">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@docsearch/css@3">
<link href="https://getbootstrap.com/docs/5.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<!-- Favicons -->
<link rel="apple-touch-icon" href="https://getbootstrap.com/docs/5.3/assets/img/favicons/apple-touch-icon.png" sizes="180x180">
<link rel="icon" href="https://getbootstrap.com/docs/5.3/assets/img/favicons/favicon-32x32.png" sizes="32x32" type="image/png">
<link rel="icon" href="https://getbootstrap.com/docs/5.3/assets/img/favicons/favicon-16x16.png" sizes="16x16" type="image/png">
<link rel="manifest" href="https://getbootstrap.com/docs/5.3/assets/img/favicons/manifest.json">
<link rel="mask-icon" href="https://getbootstrap.com/docs/5.3/assets/img/favicons/safari-pinned-tab.svg" color="#712cf9">
<link rel="icon" href="https://getbootstrap.com/docs/5.3/assets/img/favicons/favicon.ico">
<meta name="theme-color" content="#712cf9">
<style>
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
@media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
.b-example-divider {
width: 100%;
height: 3rem;
background-color: rgba(0, 0, 0, .1);
border: solid rgba(0, 0, 0, .15);
border-width: 1px 0;
box-shadow: inset 0 .5em 1.5em rgba(0, 0, 0, .1), inset 0 .125em .5em rgba(0, 0, 0, .15);
}
.b-example-vr {
flex-shrink: 0;
width: 1.5rem;
height: 100vh;
}
.bi {
vertical-align: -.125em;
fill: currentColor;
}
.nav-scroller {
position: relative;
z-index: 2;
height: 2.75rem;
overflow-y: hidden;
}
.nav-scroller .nav {
display: flex;
flex-wrap: nowrap;
padding-bottom: 1rem;
margin-top: -1px;
overflow-x: auto;
text-align: center;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
}
.btn-bd-primary {
--bd-violet-bg: #712cf9;
--bd-violet-rgb: 112.520718, 44.062154, 249.437846;
--bs-btn-font-weight: 600;
--bs-btn-color: var(--bs-white);
--bs-btn-bg: var(--bd-violet-bg);
--bs-btn-border-color: var(--bd-violet-bg);
--bs-btn-hover-color: var(--bs-white);
--bs-btn-hover-bg: #6528e0;
--bs-btn-hover-border-color: #6528e0;
--bs-btn-focus-shadow-rgb: var(--bd-violet-rgb);
--bs-btn-active-color: var(--bs-btn-hover-color);
--bs-btn-active-bg: #5a23c8;
--bs-btn-active-border-color: #5a23c8;
}
.bd-mode-toggle {
z-index: 1500;
}
.bd-mode-toggle .dropdown-menu .active .bi {
display: block !important;
}
</style>
<!-- Custom styles for this template -->
<link href="list-groups.css" rel="stylesheet">
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" class="d-none">
<symbol id="check2" viewBox="0 0 16 16">
<path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/>
</symbol>
<symbol id="circle-half" viewBox="0 0 16 16">
<path d="M8 15A7 7 0 1 0 8 1v14zm0 1A8 8 0 1 1 8 0a8 8 0 0 1 0 16z"/>
</symbol>
<symbol id="moon-stars-fill" viewBox="0 0 16 16">
<path d="M6 .278a.768.768 0 0 1 .08.858 7.208 7.208 0 0 0-.878 3.46c0 4.021 3.278 7.277 7.318 7.277.527 0 1.04-.055 1.533-.16a.787.787 0 0 1 .81.316.733.733 0 0 1-.031.893A8.349 8.349 0 0 1 8.344 16C3.734 16 0 12.286 0 7.71 0 4.266 2.114 1.312 5.124.06A.752.752 0 0 1 6 .278z"/>
<path d="M10.794 3.148a.217.217 0 0 1 .412 0l.387 1.162c.173.518.579.924 1.097 1.097l1.162.387a.217.217 0 0 1 0 .412l-1.162.387a1.734 1.734 0 0 0-1.097 1.097l-.387 1.162a.217.217 0 0 1-.412 0l-.387-1.162A1.734 1.734 0 0 0 9.31 6.593l-1.162-.387a.217.217 0 0 1 0-.412l1.162-.387a1.734 1.734 0 0 0 1.097-1.097l.387-1.162zM13.863.099a.145.145 0 0 1 .274 0l.258.774c.115.346.386.617.732.732l.774.258a.145.145 0 0 1 0 .274l-.774.258a1.156 1.156 0 0 0-.732.732l-.258.774a.145.145 0 0 1-.274 0l-.258-.774a1.156 1.156 0 0 0-.732-.732l-.774-.258a.145.145 0 0 1 0-.274l.774-.258c.346-.115.617-.386.732-.732L13.863.1z"/>
</symbol>
<symbol id="sun-fill" viewBox="0 0 16 16">
<path d="M8 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0zm0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13zm8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5zM3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8zm10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0zm-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0zm9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707zM4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708z"/>
</symbol>
</svg>
<div class="dropdown position-fixed bottom-0 end-0 mb-3 me-3 bd-mode-toggle">
<button class="btn btn-bd-primary py-2 dropdown-toggle d-flex align-items-center"
id="bd-theme"
type="button"
aria-expanded="false"
data-bs-toggle="dropdown"
aria-label="Toggle theme (auto)">
<svg class="bi my-1 theme-icon-active" width="1em" height="1em"><use href="#circle-half"></use></svg>
<span class="visually-hidden" id="bd-theme-text">Toggle theme</span>
</button>
<ul class="dropdown-menu dropdown-menu-end shadow" aria-labelledby="bd-theme-text">
<li>
<button type="button" class="dropdown-item d-flex align-items-center" data-bs-theme-value="light" aria-pressed="false">
<svg class="bi me-2 opacity-50" width="1em" height="1em"><use href="#sun-fill"></use></svg>
Light
<svg class="bi ms-auto d-none" width="1em" height="1em"><use href="#check2"></use></svg>
</button>
</li>
<li>
<button type="button" class="dropdown-item d-flex align-items-center" data-bs-theme-value="dark" aria-pressed="false">
<svg class="bi me-2 opacity-50" width="1em" height="1em"><use href="#moon-stars-fill"></use></svg>
Dark
<svg class="bi ms-auto d-none" width="1em" height="1em"><use href="#check2"></use></svg>
</button>
</li>
<li>
<button type="button" class="dropdown-item d-flex align-items-center active" data-bs-theme-value="auto" aria-pressed="true">
<svg class="bi me-2 opacity-50" width="1em" height="1em"><use href="#circle-half"></use></svg>
Auto
<svg class="bi ms-auto d-none" width="1em" height="1em"><use href="#check2"></use></svg>
</button>
</li>
</ul>
</div>
<svg xmlns="http://www.w3.org/2000/svg" class="d-none">
<symbol id="calendar-event" viewBox="0 0 16 16">
<path d="M11 6.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1z"/>
<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z"/>
</symbol>
<symbol id="alarm" viewBox="0 0 16 16">
<path d="M8.5 5.5a.5.5 0 0 0-1 0v3.362l-1.429 2.38a.5.5 0 1 0 .858.515l1.5-2.5A.5.5 0 0 0 8.5 9V5.5z"/>
<path d="M6.5 0a.5.5 0 0 0 0 1H7v1.07a7.001 7.001 0 0 0-3.273 12.474l-.602.602a.5.5 0 0 0 .707.708l.746-.746A6.97 6.97 0 0 0 8 16a6.97 6.97 0 0 0 3.422-.892l.746.746a.5.5 0 0 0 .707-.708l-.601-.602A7.001 7.001 0 0 0 9 2.07V1h.5a.5.5 0 0 0 0-1h-3zm1.038 3.018a6.093 6.093 0 0 1 .924 0 6 6 0 1 1-.924 0zM0 3.5c0 .753.333 1.429.86 1.887A8.035 8.035 0 0 1 4.387 1.86 2.5 2.5 0 0 0 0 3.5zM13.5 1c-.753 0-1.429.333-1.887.86a8.035 8.035 0 0 1 3.527 3.527A2.5 2.5 0 0 0 13.5 1z"/>
</symbol>
<symbol id="list-check" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M5 11.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zM3.854 2.146a.5.5 0 0 1 0 .708l-1.5 1.5a.5.5 0 0 1-.708 0l-.5-.5a.5.5 0 1 1 .708-.708L2 3.293l1.146-1.147a.5.5 0 0 1 .708 0zm0 4a.5.5 0 0 1 0 .708l-1.5 1.5a.5.5 0 0 1-.708 0l-.5-.5a.5.5 0 1 1 .708-.708L2 7.293l1.146-1.147a.5.5 0 0 1 .708 0zm0 4a.5.5 0 0 1 0 .708l-1.5 1.5a.5.5 0 0 1-.708 0l-.5-.5a.5.5 0 0 1 .708-.708l.146.147 1.146-1.147a.5.5 0 0 1 .708 0z"/>
</symbol>
</svg>
<div class="d-flex flex-column flex-md-row p-4 gap-4 py-md-5 align-items-center justify-content-center">
<div class="list-group">
<a href="#" class="list-group-item list-group-item-action d-flex gap-3 py-3" aria-current="true">
<img src="https://github.com/twbs.png" alt="twbs" width="32" height="32" class="rounded-circle flex-shrink-0">
<div class="d-flex gap-2 w-100 justify-content-between">
<div>
<h6 class="mb-0">List group item heading</h6>
<p class="mb-0 opacity-75">Some placeholder content in a paragraph.</p>
</div>
<small class="opacity-50 text-nowrap">now</small>
</div>
</a>
<a href="#" class="list-group-item list-group-item-action d-flex gap-3 py-3" aria-current="true">
<img src="https://github.com/twbs.png" alt="twbs" width="32" height="32" class="rounded-circle flex-shrink-0">
<div class="d-flex gap-2 w-100 justify-content-between">
<div>
<h6 class="mb-0">Another title here</h6>
<p class="mb-0 opacity-75">Some placeholder content in a paragraph that goes a little longer so it wraps to a new line.</p>
</div>
<small class="opacity-50 text-nowrap">3d</small>
</div>
</a>
<a href="#" class="list-group-item list-group-item-action d-flex gap-3 py-3" aria-current="true">
<img src="https://github.com/twbs.png" alt="twbs" width="32" height="32" class="rounded-circle flex-shrink-0">
<div class="d-flex gap-2 w-100 justify-content-between">
<div>
<h6 class="mb-0">Third heading</h6>
<p class="mb-0 opacity-75">Some placeholder content in a paragraph.</p>
</div>
<small class="opacity-50 text-nowrap">1w</small>
</div>
</a>
</div>
</div>
<div class="b-example-divider"></div>
<div class="d-flex flex-column flex-md-row p-4 gap-4 py-md-5 align-items-center justify-content-center">
<div class="list-group">
<label class="list-group-item d-flex gap-2">
<input class="form-check-input flex-shrink-0" type="checkbox" value="" checked>
<span>
First checkbox
<small class="d-block text-body-secondary">With support text underneath to add more detail</small>
</span>
</label>
<label class="list-group-item d-flex gap-2">
<input class="form-check-input flex-shrink-0" type="checkbox" value="">
<span>
Second checkbox
<small class="d-block text-body-secondary">Some other text goes here</small>
</span>
</label>
<label class="list-group-item d-flex gap-2">
<input class="form-check-input flex-shrink-0" type="checkbox" value="">
<span>
Third checkbox
<small class="d-block text-body-secondary">And we end with another snippet of text</small>
</span>
</label>
</div>
<div class="list-group">
<label class="list-group-item d-flex gap-2">
<input class="form-check-input flex-shrink-0" type="radio" name="listGroupRadios" id="listGroupRadios1" value="" checked>
<span>
First radio
<small class="d-block text-body-secondary">With support text underneath to add more detail</small>
</span>
</label>
<label class="list-group-item d-flex gap-2">
<input class="form-check-input flex-shrink-0" type="radio" name="listGroupRadios" id="listGroupRadios2" value="">
<span>
Second radio
<small class="d-block text-body-secondary">Some other text goes here</small>
</span>
</label>
<label class="list-group-item d-flex gap-2">
<input class="form-check-input flex-shrink-0" type="radio" name="listGroupRadios" id="listGroupRadios3" value="">
<span>
Third radio
<small class="d-block text-body-secondary">And we end with another snippet of text</small>
</span>
</label>
</div>
</div>
<div class="b-example-divider"></div>
<div class="d-flex flex-column flex-md-row p-4 gap-4 py-md-5 align-items-center justify-content-center">
<div class="list-group">
<label class="list-group-item d-flex gap-3">
<input class="form-check-input flex-shrink-0" type="checkbox" value="" checked style="font-size: 1.375em;">
<span class="pt-1 form-checked-content">
<strong>Finish sales report</strong>
<small class="d-block text-body-secondary">
<svg class="bi me-1" width="1em" height="1em"><use xlink:href="#calendar-event"/></svg>
1:002:00pm
</small>
</span>
</label>
<label class="list-group-item d-flex gap-3">
<input class="form-check-input flex-shrink-0" type="checkbox" value="" style="font-size: 1.375em;">
<span class="pt-1 form-checked-content">
<strong>Weekly All Hands</strong>
<small class="d-block text-body-secondary">
<svg class="bi me-1" width="1em" height="1em"><use xlink:href="#calendar-event"/></svg>
2:002:30pm
</small>
</span>
</label>
<label class="list-group-item d-flex gap-3">
<input class="form-check-input flex-shrink-0" type="checkbox" value="" style="font-size: 1.375em;">
<span class="pt-1 form-checked-content">
<strong>Out of office</strong>
<small class="d-block text-body-secondary">
<svg class="bi me-1" width="1em" height="1em"><use xlink:href="#alarm"/></svg>
Tomorrow
</small>
</span>
</label>
<label class="list-group-item d-flex gap-3 bg-body-tertiary">
<input class="form-check-input form-check-input-placeholder bg-body-tertiary flex-shrink-0 pe-none" disabled type="checkbox" value="" style="font-size: 1.375em;">
<span class="pt-1 form-checked-content">
<span contenteditable="true" class="w-100">Add new task...</span>
<small class="d-block text-body-secondary">
<svg class="bi me-1" width="1em" height="1em"><use xlink:href="#list-check"/></svg>
Choose list...
</small>
</span>
</label>
</div>
</div>
<div class="b-example-divider"></div>
<div class="d-flex flex-column flex-md-row p-4 gap-4 py-md-5 align-items-center justify-content-center">
<div class="list-group list-group-checkable d-grid gap-2 border-0">
<input class="list-group-item-check pe-none" type="radio" name="listGroupCheckableRadios" id="listGroupCheckableRadios1" value="" checked>
<label class="list-group-item rounded-3 py-3" for="listGroupCheckableRadios1">
First radio
<span class="d-block small opacity-50">With support text underneath to add more detail</span>
</label>
<input class="list-group-item-check pe-none" type="radio" name="listGroupCheckableRadios" id="listGroupCheckableRadios2" value="">
<label class="list-group-item rounded-3 py-3" for="listGroupCheckableRadios2">
Second radio
<span class="d-block small opacity-50">Some other text goes here</span>
</label>
<input class="list-group-item-check pe-none" type="radio" name="listGroupCheckableRadios" id="listGroupCheckableRadios3" value="">
<label class="list-group-item rounded-3 py-3" for="listGroupCheckableRadios3">
Third radio
<span class="d-block small opacity-50">And we end with another snippet of text</span>
</label>
<input class="list-group-item-check pe-none" type="radio" name="listGroupCheckableRadios" id="listGroupCheckableRadios4" value="" disabled>
<label class="list-group-item rounded-3 py-3" for="listGroupCheckableRadios4">
Fourth disabled radio
<span class="d-block small opacity-50">This option is disabled</span>
</label>
</div>
</div>
<div class="b-example-divider"></div>
<div class="d-flex flex-column flex-md-row p-4 gap-4 py-md-5 align-items-center justify-content-center">
<div class="list-group list-group-radio d-grid gap-2 border-0">
<div class="position-relative">
<input class="form-check-input position-absolute top-50 end-0 me-3 fs-5" type="radio" name="listGroupRadioGrid" id="listGroupRadioGrid1" value="" checked>
<label class="list-group-item py-3 pe-5" for="listGroupRadioGrid1">
<strong class="fw-semibold">First radio</strong>
<span class="d-block small opacity-75">With support text underneath to add more detail</span>
</label>
</div>
<div class="position-relative">
<input class="form-check-input position-absolute top-50 end-0 me-3 fs-5" type="radio" name="listGroupRadioGrid" id="listGroupRadioGrid2" value="">
<label class="list-group-item py-3 pe-5" for="listGroupRadioGrid2">
<strong class="fw-semibold">Second radio</strong>
<span class="d-block small opacity-75">Some other text goes here</span>
</label>
</div>
<div class="position-relative">
<input class="form-check-input position-absolute top-50 end-0 me-3 fs-5" type="radio" name="listGroupRadioGrid" id="listGroupRadioGrid3" value="">
<label class="list-group-item py-3 pe-5" for="listGroupRadioGrid3">
<strong class="fw-semibold">Third radio</strong>
<span class="d-block small opacity-75">And we end with another snippet of text</span>
</label>
</div>
<div class="position-relative">
<input class="form-check-input position-absolute top-50 end-0 me-3 fs-5" type="radio" name="listGroupRadioGrid" id="listGroupRadioGrid4" value="" disabled>
<label class="list-group-item py-3 pe-5" for="listGroupRadioGrid4">
<strong class="fw-semibold">Fourth disabled radio</strong>
<span class="d-block small opacity-75">This option is disabled</span>
</label>
</div>
</div>
</div>
<script src="https://getbootstrap.com/docs/5.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
</body>
</html>

View File

@ -0,0 +1,86 @@
<!DOCTYPE html>
<html lang="en" data-bs-theme="dark">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
<title>Testapp</title>
<style>
.darker-bg {
background-color: #171a1e;
}
.list-group {
width: 100%;
max-width: 460px;
margin-inline: 1.5rem;
}
.list-group-checkable .list-group-item {
cursor: pointer;
}
.list-group-item-check {
position: absolute;
clip: rect(0, 0, 0, 0);
}
.list-group-item-check:hover + .list-group-item {
background-color: var(--bs-secondary-bg);
}
.list-group-item-check:checked + .list-group-item {
color: #fff;
background-color: var(--bs-primary);
border-color: var(--bs-primary);
}
.list-group-item-check[disabled] + .list-group-item,
.list-group-item-check:disabled + .list-group-item {
pointer-events: none;
filter: none;
opacity: .5;
}
.list-group-radio .list-group-item {
cursor: pointer;
border-radius: .5rem;
}
.list-group-radio .form-check-input {
z-index: 2;
margin-top: -.5em;
}
.list-group-radio .list-group-item:hover,
.list-group-radio .list-group-item:focus {
background-color: var(--bs-secondary-bg);
}
.list-group-radio .form-check-input:checked + .list-group-item {
background-color: var(--bs-body);
border-color: var(--bs-primary);
box-shadow: 0 0 0 2px var(--bs-primary);
}
.list-group-radio .form-check-input[disabled] + .list-group-item,
.list-group-radio .form-check-input:disabled + .list-group-item {
pointer-events: none;
filter: none;
opacity: .5;
}
</style>
</head>
<body>
<div class="px-4 py-5 my-5 text-center shadow darker-bg">
<h1 class="display-5 fw-bold text-body-emphasis">{{ question.question_text }}</h1>
<br/>
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
<fieldset class="d-flex flex-column flex-md-row col-lg-6 mx-auto align-items-center justify-content-center">
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<div class="list-group list-group-checkable d-grid gap-2 border-0">
{% for choice in question.choice_set.all %}
<input class="list-group-item-check pe-none" type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
<label class="list-group-item rounded-3 py-3" for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
{% endfor %}
</div>
</fieldset>
<br/>
<input class="btn btn-success rounded-3 px-3" type="submit" value="Vote">
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en" data-bs-theme="dark">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
<title>Testapp</title>
<style>
.darker-bg {
background-color: #171a1e;
}
</style>
</head>
<body>
<div class="px-4 py-5 my-5 shadow darker-bg">
<h1 class="display-5 fw-bold text-body-emphasis text-center">Polls</h1>
<br/>
<div class="d-flex flex-column flex-md-row col-lg-6 mx-auto align-items-center justify-content-center">
{% if latest_question_list %}
<div class="list-group">
{% for question in latest_question_list %}
<a href="{% url 'polls:detail' question.id %}" class="list-group-item list-group-item-action d-flex gap-3 py-3" aria-current="true">
<!--<img src="https://github.com/twbs.png" alt="twbs" width="32" height="32" class="rounded-circle flex-shrink-0"> -->
<div class="d-flex gap-2 w-100 justify-content-between">
<div>
<h6 class="mb-0">{{ question.question_text }}</h6>
<!-- <p class="mb-0 opacity-75">Some placeholder content in a paragraph.</p> -->
</div>
<small class="opacity-50 text-nowrap">{{ question.pub_date }}</small>
</div>
</a>
{% endfor %}
</div>
{% else %}
<p class="text-center text-muted">
No polls are available.<br />
You can create polls in the <a href="/admin/polls/question/">admin panel</a>
</p>
{% endif %}
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,94 @@
<!doctype html>
<html lang="en" data-bs-theme="dark">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
<meta name="generator" content="Hugo 0.122.0">
<title>List groups · Bootstrap v5.3</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<!-- Custom styles for this template -->
<!--<link href="list-groups.css" rel="stylesheet">-->
<style>
.list-group {
width: 100%;
max-width: 460px;
margin-inline: 1.5rem;
}
.list-group-checkable .list-group-item {
cursor: pointer;
}
.list-group-item-check {
position: absolute;
clip: rect(0, 0, 0, 0);
}
.list-group-item-check:hover + .list-group-item {
background-color: var(--bs-secondary-bg);
}
.list-group-item-check:checked + .list-group-item {
color: #fff;
background-color: var(--bs-primary);
border-color: var(--bs-primary);
}
.list-group-item-check[disabled] + .list-group-item,
.list-group-item-check:disabled + .list-group-item {
pointer-events: none;
filter: none;
opacity: .5;
}
.list-group-radio .list-group-item {
cursor: pointer;
border-radius: .5rem;
}
.list-group-radio .form-check-input {
z-index: 2;
margin-top: -.5em;
}
.list-group-radio .list-group-item:hover,
.list-group-radio .list-group-item:focus {
background-color: var(--bs-secondary-bg);
}
.list-group-radio .form-check-input:checked + .list-group-item {
background-color: var(--bs-body);
border-color: var(--bs-primary);
box-shadow: 0 0 0 2px var(--bs-primary);
}
.list-group-radio .form-check-input[disabled] + .list-group-item,
.list-group-radio .form-check-input:disabled + .list-group-item {
pointer-events: none;
filter: none;
opacity: .5;
}
</style>
</head>
<body>
<div class="d-flex flex-column flex-md-row p-4 gap-4 py-md-5 align-items-center justify-content-center">
<div class="list-group list-group-checkable d-grid gap-2 border-0">
<input class="list-group-item-check pe-none" type="radio" name="listGroupCheckableRadios" id="listGroupCheckableRadios1" value="" checked>
<label class="list-group-item rounded-3 py-3" for="listGroupCheckableRadios1">
First radio
</label>
<input class="list-group-item-check pe-none" type="radio" name="listGroupCheckableRadios" id="listGroupCheckableRadios2" value="">
<label class="list-group-item rounded-3 py-3" for="listGroupCheckableRadios2">
Second radio
</label>
<input class="list-group-item-check pe-none" type="radio" name="listGroupCheckableRadios" id="listGroupCheckableRadios3" value="">
<label class="list-group-item rounded-3 py-3" for="listGroupCheckableRadios3">
Third radio
</label>
<input class="list-group-item-check pe-none" type="radio" name="listGroupCheckableRadios" id="listGroupCheckableRadios4" value="" disabled>
<label class="list-group-item rounded-3 py-3" for="listGroupCheckableRadios4">
Fourth disabled radio
</label>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,92 @@
<!DOCTYPE html>
<html lang="en" data-bs-theme="dark">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
<title>Testapp</title>
<style>
.darker-bg {
background-color: #171a1e;
}
.list-group {
width: 100%;
max-width: 460px;
margin-inline: 1.5rem;
}
.list-group-checkable .list-group-item {
cursor: pointer;
}
.list-group-item-check {
position: absolute;
clip: rect(0, 0, 0, 0);
}
.list-group-item-check:hover + .list-group-item {
background-color: var(--bs-secondary-bg);
}
.list-group-item-check:checked + .list-group-item {
color: #fff;
background-color: var(--bs-primary);
border-color: var(--bs-primary);
}
.list-group-item-check[disabled] + .list-group-item,
.list-group-item-check:disabled + .list-group-item {
pointer-events: none;
filter: none;
opacity: .5;
}
.list-group-radio .list-group-item {
cursor: pointer;
border-radius: .5rem;
}
.list-group-radio .form-check-input {
z-index: 2;
margin-top: -.5em;
}
.list-group-radio .list-group-item:hover,
.list-group-radio .list-group-item:focus {
background-color: var(--bs-secondary-bg);
}
.list-group-radio .form-check-input:checked + .list-group-item {
background-color: var(--bs-body);
border-color: var(--bs-primary);
box-shadow: 0 0 0 2px var(--bs-primary);
}
.list-group-radio .form-check-input[disabled] + .list-group-item,
.list-group-radio .form-check-input:disabled + .list-group-item {
pointer-events: none;
filter: none;
opacity: .5;
}
</style>
</head>
<body>
<div class="px-4 py-5 my-5 shadow darker-bg">
<h1 class="display-5 fw-bold text-body-emphasis text-center">{{ question.question_text }}</h1>
<br/>
<h1 class="text-center">Results</h1>
<div class="d-flex flex-column flex-md-row col-lg-6 mx-auto align-items-center justify-content-center">
<div class="list-group">
{% for choice_text, choice_votes, choice_percent in choices %}
<div class="list-group-item list-group-item-action d-flex gap-3 py-3">
<div class="d-flex gap-2 w-100 justify-content-between">
<div>
<h6 class="mb-0">{{ choice_text }}</h6>
<!--
<div role="progressbar" aria-label="{{ choice_text }}" aria-valuenow="{{ choice_percent }}" aria-valuemin="0" aria-valuemax="100" class="progress">
<div class="progress-bar" style="width: {{ choice_percent }}%"></div>
</div>
-->
</div>
<small class="text-nowrap">{{ choice_votes }} vote{{ choice_votes|pluralize }}</small>
</div>
</div>
{% endfor %}
</div{{ question.question_text }}>
</div>
</div>
</body>
</html>

3
polls/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

15
polls/urls.py Normal file
View File

@ -0,0 +1,15 @@
from django.urls import path
from . import views
app_name = "polls"
urlpatterns = [
path("", views.index, name="polls-index"),
# ex: /polls/5/
path("<int:question_id>/", views.detail, name="detail"),
# ex: /polls/5/results/
path("<int:question_id>/results/", views.results, name="results"),
# ex: /polls/5/vote/
path("<int:question_id>/vote/", views.vote, name="vote"),
]

41
polls/views.py Normal file
View File

@ -0,0 +1,41 @@
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse, HttpResponseRedirect
from django.urls import reverse
from django.db.models import F
from .models import Question, Choice
# Create your views here.
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)
# get all the choices and their votes
choices = question.choice_set.all()
max = 0
for choice in choices:
if choice.votes > max:
max = choice.votes
choice_data = [(choice.choice_text, choice.votes, choice.votes / max * 100) for choice in choices]
return render(request, "polls/results.html", {"question": question, "max_votes": max, "choices": choice_data})
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):
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()
return HttpResponseRedirect(reverse("polls:results", args=(question.id,)))