├── mysite ├── __init__.py ├── wsgi.py ├── urls.py └── settings.py ├── poll ├── __init__.py ├── migrations │ ├── __init__.py │ ├── 0002_auto_20151130_0539.py │ ├── 0003_auto_20151130_0540.py │ └── 0001_initial.py ├── apps.py ├── urls.py ├── admin.py ├── models.py ├── templates │ └── polls │ │ ├── results.html │ │ ├── detail.html │ │ └── index.html ├── tests.py └── views.py ├── manage.py ├── .gitignore └── README.md /mysite/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /poll/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /poll/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /poll/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class PollConfig(AppConfig): 5 | name = 'poll' 6 | -------------------------------------------------------------------------------- /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", "mysite.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /mysite/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for mysite 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/dev/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", "mysite.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /poll/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | 3 | from . import views 4 | 5 | urlpatterns = [ 6 | # ex: /polls/ 7 | url(r'^$', views.IndexView.as_view(), name='index'), 8 | # ex: /polls/5/ 9 | url(r'^(?P[0-9]+)/$', views.DetailView.as_view(), name='detail'), 10 | # ex:/polls/5/results/ 11 | url(r'^(?P[0-9]+)/results/$', views.ResultsView.as_view(), name='results'), 12 | # ex:/polls/5/vote/ 13 | url(r'^(?P[0-9]+)/vote/$', views.vote, name='vote') 14 | ] -------------------------------------------------------------------------------- /poll/migrations/0002_auto_20151130_0539.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.dev20151128133845 on 2015-11-30 05:39 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('poll', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RenameField( 16 | model_name='question', 17 | old_name='question_text', 18 | new_name='question_textssssss', 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /poll/migrations/0003_auto_20151130_0540.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.dev20151128133845 on 2015-11-30 05:40 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('poll', '0002_auto_20151130_0539'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RenameField( 16 | model_name='question', 17 | old_name='question_textssssss', 18 | new_name='question_text', 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /poll/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from .models import Question, Choice 4 | 5 | 6 | class ChoiceInline(admin.TabularInline): 7 | model = Choice 8 | extra = 3 9 | 10 | 11 | # Register your models here. 12 | class QuestionAdmin(admin.ModelAdmin): 13 | fieldsets = [ 14 | (None, {'fields': ['question_text']}), 15 | ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}) 16 | ] 17 | list_display = ('question_text', 'pub_date', 'was_published_recently') 18 | list_filter = ['pub_date'] 19 | search_fields = ['question_text'] 20 | inlines = [ChoiceInline] 21 | 22 | 23 | admin.site.register(Question, QuestionAdmin) 24 | 25 | 26 | -------------------------------------------------------------------------------- /poll/models.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | from django.db import models 4 | from django.utils import timezone 5 | 6 | 7 | # Create your models here. 8 | # model for question 9 | class Question(models.Model): 10 | question_text = models.CharField(max_length=200) 11 | pub_date = models.DateTimeField('date published') 12 | 13 | def __str__(self): 14 | return self.question_text 15 | 16 | def was_published_recently(self): 17 | return timezone.now() >= self.pub_date >= timezone.now() - datetime.timedelta(days=1) 18 | 19 | 20 | # model for choice, related to question 21 | class Choice(models.Model): 22 | question = models.ForeignKey(Question) 23 | choice_text = models.CharField(max_length=200) 24 | votes = models.IntegerField(default=0) 25 | 26 | def __str__(self): 27 | return self.choice_text 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /mysite/urls.py: -------------------------------------------------------------------------------- 1 | """mysite URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/dev/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: url(r'^$', 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: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Add an import: from blog import urls as blog_urls 14 | 2. Import the include() function: from django.conf.urls import url, include 15 | 3. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls)) 16 | """ 17 | from django.conf.urls import include, url 18 | from django.contrib import admin 19 | 20 | urlpatterns = [ 21 | url(r'^polls/', include('poll.urls', namespace="polls")), 22 | url(r'^admin/', admin.site.urls), 23 | ] 24 | -------------------------------------------------------------------------------- /poll/templates/polls/results.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | poll system index 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 | 投票问题:{{ question.question_text }} 18 |
19 |
    20 | {% for choice in question.choice_set.all %} 21 |
  • {{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}
  • 22 | {% endfor %} 23 |
24 | 25 | Vote again? 26 |
27 |
28 | 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 2 | 3 | *.pyc 4 | *.iml 5 | 6 | ## Directory-based project format: 7 | .idea/ 8 | # if you remove the above rule, at least ignore the following: 9 | 10 | # User-specific stuff: 11 | # .idea/workspace.xml 12 | # .idea/tasks.xml 13 | # .idea/dictionaries 14 | # .idea/shelf 15 | 16 | # Sensitive or high-churn files: 17 | # .idea/dataSources.ids 18 | # .idea/dataSources.xml 19 | # .idea/sqlDataSources.xml 20 | # .idea/dynamic.xml 21 | # .idea/uiDesigner.xml 22 | 23 | # Gradle: 24 | # .idea/gradle.xml 25 | # .idea/libraries 26 | 27 | # Mongo Explorer plugin: 28 | # .idea/mongoSettings.xml 29 | 30 | ## File-based project format: 31 | *.ipr 32 | *.iws 33 | 34 | ## Plugin-specific files: 35 | 36 | # IntelliJ 37 | /out/ 38 | 39 | # mpeltonen/sbt-idea plugin 40 | .idea_modules/ 41 | 42 | # JIRA plugin 43 | atlassian-ide-plugin.xml 44 | 45 | # Crashlytics plugin (for Android Studio and IntelliJ) 46 | com_crashlytics_export_strings.xml 47 | crashlytics.properties 48 | crashlytics-build.properties 49 | fabric.properties 50 | -------------------------------------------------------------------------------- /poll/tests.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | from django.test import TestCase 4 | from django.utils import timezone 5 | 6 | from .models import Question 7 | 8 | 9 | # Create your tests here. 10 | class QuestionMethodTests(TestCase): 11 | 12 | def test_was_published_recently_with_future_question(self): 13 | # when a question's pub_date is in future, was_published_recently()should return false 14 | time = timezone.now() + datetime.timedelta(days=30) 15 | future_question = Question(pub_date=time) 16 | self.assertEquals(future_question.was_published_recently(), False) 17 | 18 | def test_was_published_recently_with_old_question(self): 19 | time = timezone.now() - datetime.timedelta(days=30) 20 | old_question = Question(pub_date=time) 21 | self.assertEquals(old_question.was_published_recently(), False) 22 | 23 | def test_was_published_recently_with_recent_question(self): 24 | time = timezone.now() - datetime.timedelta(hours=1) 25 | recent_question = Question(pub_date=time) 26 | self.assertEqual(recent_question.was_published_recently(), True) 27 | 28 | 29 | -------------------------------------------------------------------------------- /poll/templates/polls/detail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | poll system index 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 | 投票问题:{{ question.question_text }} 18 |
19 | 20 | {% if error_message %}

{{ error_message }}

{% endif %} 21 | 22 |
23 | {% csrf_token %} 24 | {% for choice in question.choice_set.all %} 25 | 26 |
27 | {% endfor %} 28 | 29 |
30 |
31 |
32 | 33 | -------------------------------------------------------------------------------- /poll/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.dev20151128133845 on 2015-11-30 03:23 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import django.db.models.deletion 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | initial = True 12 | 13 | dependencies = [ 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='Choice', 19 | fields=[ 20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 | ('choice_text', models.CharField(max_length=200)), 22 | ('votes', models.IntegerField(default=0)), 23 | ], 24 | ), 25 | migrations.CreateModel( 26 | name='Question', 27 | fields=[ 28 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 29 | ('question_text', models.CharField(max_length=200)), 30 | ('pub_date', models.DateTimeField(verbose_name='date published')), 31 | ], 32 | ), 33 | migrations.AddField( 34 | model_name='choice', 35 | name='question', 36 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='poll.Question'), 37 | ), 38 | ] 39 | -------------------------------------------------------------------------------- /poll/templates/polls/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | poll system index 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 26 | 27 | {% if latest_question_list %} 28 | 34 | {% else %} 35 |

No polls are available.

36 | {% endif %} 37 |
38 | 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PollSystemDemo 2 | 根据Django官方的教程写的投票系统 真的要被Django吸粉了 3 | 4 | ### 运行投票系统 5 | 1.安装python,MySQL-python, gunicorn(可选) 6 | 2.clone 项目 7 | 8 | ``` 9 | $ cd worksapce 10 | $ git clone git@github.com:giraffe0813/PollSystemDemo.git 11 | ``` 12 | 3.修改setting.py文件中的数据库配置 13 | 14 | ``` 15 | $ cd PollSystemDemo/mysite 16 | $ vi setting.py 17 | ``` 18 | 依据实际使用的数据库地址,用户,密码修改下面的配置 19 | 20 | ```json 21 | 22 | DATABASES = { 23 | 'default': { 24 | 'ENGINE': 'django.db.backends.mysql', 25 | 'NAME': 'mydatabase', 26 | 'USER': 'root', 27 | 'PASSWORD': 'coffee', 28 | 'HOST': '127.0.0.1', 29 | 'PORT': '3306', 30 | } 31 | } 32 | 33 | ``` 34 | 35 | 4.建表 36 | 37 | 执行下面的命令会在上面配置的数据库中新建多张表 38 | 39 | ``` 40 | $ cd PollSystemDemo 41 | $ python manage.py migrate 42 | ``` 43 | 44 | 5.运行 45 | 两种方法 46 | 47 | * 最简单的方法 48 | 49 | ``` 50 | $ pyhton manage.py runserver 51 | ``` 52 | * 第二种方法 需要安装gunicorn 53 | 54 | ``` 55 | $ gunicorn mysite.wsgi:application -b 127.0.0.1:8000 --reload 56 | ``` 57 | 58 | 59 | 60 | 61 | 6 访问 62 | 浏览器中访问 localhost:8000 即可 63 | 64 | ### 使用投票系统管理后台 65 | 66 | 1 创建管理员账号 67 | ``` 68 | $ cd PollSystemDemo 69 | $ python manage.py createsuperuser 70 | ``` 71 | 按照提示设置用户名,邮箱和密码 72 | 73 | 2 运行项目 74 | 75 | * 最简单的方法 76 | 77 | ``` 78 | $ pyhton manage.py runserver 79 | ``` 80 | * 第二种方法 需要安装gunicorn 81 | 82 | ``` 83 | $ gunicorn mysite.wsgi:application -b 127.0.0.1:8000 --relo 84 | ``` 85 | 86 | 3 访问管理后台 87 | 88 | 浏览器访问 localhost:8000/admin 89 | 按照第一步设置的用户名和密码登陆就可以使用管理系统了 90 | 91 | 🎅 92 | 93 | -------------------------------------------------------------------------------- /poll/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render, get_object_or_404 2 | from django.http import HttpResponse, HttpResponseRedirect 3 | from .models import Question, Choice 4 | from django.core.urlresolvers import reverse 5 | from django.views import generic 6 | from django.utils import timezone 7 | 8 | 9 | # Create your views here. 10 | def index(request): 11 | latest_question_list = Question.objects.order_by('-pub_date')[:5] 12 | context = { 13 | 'latest_question_list': latest_question_list 14 | } 15 | return render(request, 'polls/index.html', context) 16 | 17 | 18 | def detail(request, question_id): 19 | question = get_object_or_404(Question, pk=question_id) 20 | return render(request, 'polls/detail.html', {'question': question}) 21 | 22 | 23 | def results(request, question_id): 24 | question = get_object_or_404(Question, pk=question_id) 25 | return render(request, 'polls/results.html', {'question': question}) 26 | 27 | 28 | def vote(request, question_id): 29 | p = get_object_or_404(Question, pk=question_id) 30 | try: 31 | selected_choice = p.choice_set.get(pk=request.POST["choice"]) 32 | except (KeyError, Choice.DoesNotExist): 33 | return render(request, 'polls/detail.html', { 34 | 'question': p, 35 | 'error_message': "You didn't select a choice." 36 | }) 37 | selected_choice.votes += 1 38 | selected_choice.save() 39 | # success deal with post data always return HttpResponseRedirect, prevent user submit twice 40 | return HttpResponseRedirect(reverse('polls:results', args=(p.id,))) 41 | 42 | 43 | # ListView represent display a list of objects 44 | class IndexView(generic.ListView): 45 | template_name = 'polls/index.html' 46 | context_object_name = 'latest_question_list' 47 | 48 | def get_queryset(self): 49 | # return last five published question 50 | return Question.objects.filter( 51 | pub_date__lte=timezone.now() 52 | ).order_by('-pub_date')[:5] 53 | 54 | 55 | # DetailView represent display a detail page for a particular type of object 56 | # 57 | class DetailView(generic.DetailView): 58 | model = Question 59 | template_name = 'polls/detail.html' 60 | 61 | 62 | class ResultsView(generic.DetailView): 63 | model = Question 64 | template_name = 'polls/results.html' 65 | 66 | 67 | -------------------------------------------------------------------------------- /mysite/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for mysite project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.10.dev20151128133845. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/dev/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/dev/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/dev/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = '!k*0bb+j-pt+s2iqy9bgpvngs(p@i3a@$=&=z5r(f2gh^^bse%' 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 | 'poll', 41 | 'gunicorn', 42 | ] 43 | 44 | MIDDLEWARE_CLASSES = [ 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 = 'mysite.urls' 55 | 56 | TEMPLATES = [ 57 | { 58 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 59 | 'DIRS': [], 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 = 'mysite.wsgi.application' 73 | 74 | 75 | # Database 76 | # https://docs.djangoproject.com/en/dev/ref/settings/#databases 77 | 78 | DATABASES = { 79 | 'default': { 80 | 'ENGINE': 'django.db.backends.mysql', 81 | 'NAME': 'mydatabase', 82 | 'USER': 'root', 83 | 'PASSWORD': 'coffee', 84 | 'HOST': '127.0.0.1', 85 | 'PORT': '3306', 86 | } 87 | } 88 | 89 | 90 | # Password validation 91 | # https://docs.djangoproject.com/en/dev/ref/settings/#auth-password-validators 92 | 93 | AUTH_PASSWORD_VALIDATORS = [ 94 | { 95 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 96 | }, 97 | { 98 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 99 | }, 100 | { 101 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 102 | }, 103 | { 104 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 105 | }, 106 | ] 107 | 108 | 109 | # Internationalization 110 | # https://docs.djangoproject.com/en/dev/topics/i18n/ 111 | 112 | LANGUAGE_CODE = 'en-us' 113 | 114 | TIME_ZONE = 'UTC' 115 | 116 | USE_I18N = True 117 | 118 | USE_L10N = True 119 | 120 | USE_TZ = True 121 | 122 | 123 | # Static files (CSS, JavaScript, Images) 124 | # https://docs.djangoproject.com/en/dev/howto/static-files/ 125 | 126 | STATIC_URL = '/static/' 127 | --------------------------------------------------------------------------------