├── polls
├── __init__.py
├── static
│ └── polls
│ │ └── style.css
├── templates
│ └── polls
│ │ ├── results.html
│ │ ├── index.html
│ │ └── detail.html
├── urls.py
├── admin.py
├── models.py
├── views.py
└── tests.py
├── .idea
├── .name
├── vcs.xml
├── modules.xml
├── misc.xml
└── first_steps.iml
├── first_steps
├── __init__.py
├── urls.py
├── wsgi.py
└── settings.py
├── manage.py
└── playing_with_API.py
/polls/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | first_steps
--------------------------------------------------------------------------------
/first_steps/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/polls/static/polls/style.css:
--------------------------------------------------------------------------------
1 | li a {
2 | color: green;
3 | }
4 | body {
5 | background: white url("images/background.gif") no-repeat right bottom;
6 | }
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
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", "first_steps.settings")
7 |
8 | from django.core.management import execute_from_command_line
9 |
10 | execute_from_command_line(sys.argv)
11 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/polls/templates/polls/results.html:
--------------------------------------------------------------------------------
1 |
{{ question.question_text }}
2 |
3 |
4 | {% for choice in question.choice_set.all %}
5 | - {{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}
6 | {% endfor %}
7 |
8 |
9 | Vote again?
--------------------------------------------------------------------------------
/polls/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url
2 |
3 | from . import views
4 |
5 | urlpatterns = [
6 | url(r'^$', views.IndexView.as_view(), name='index'),
7 | url(r'^(?P[0-9]+)/$', views.DetailView.as_view(), name='detail'),
8 | url(r'^(?P[0-9]+)/results/$', views.ResultsView.as_view(), name='results'),
9 | url(r'^(?P[0-9]+)/vote/$', views.vote, name='vote'),
10 | ]
--------------------------------------------------------------------------------
/first_steps/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import patterns, include, url
2 |
3 | from django.contrib import admin
4 | admin.autodiscover()
5 |
6 | urlpatterns = patterns('',
7 | # Examples:
8 | # url(r'^$', 'first_steps.views.home', name='home'),
9 | # url(r'^blog/', include('blog.urls')),
10 |
11 | url(r'^polls/', include('polls.urls', namespace='polls')),
12 | url(r'^admin/', include(admin.site.urls)),
13 | )
14 |
--------------------------------------------------------------------------------
/polls/templates/polls/index.html:
--------------------------------------------------------------------------------
1 | {% load staticfiles %}
2 |
3 |
4 |
5 | {% if latest_question_list %}
6 |
11 | {% else %}
12 | No polls are available.
13 | {% endif %}
--------------------------------------------------------------------------------
/first_steps/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for first_steps 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/1.6/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "first_steps.settings")
12 |
13 | from django.core.wsgi import get_wsgi_application
14 | application = get_wsgi_application()
15 |
--------------------------------------------------------------------------------
/polls/templates/polls/detail.html:
--------------------------------------------------------------------------------
1 | {{ question.question_text }}
2 |
3 | {% if error_message %}{{ error_message }}
{% endif %}
4 |
5 |
13 |
--------------------------------------------------------------------------------
/polls/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | from .models import Question, Choice
4 |
5 |
6 | class ChoiceInline(admin.StackedInline):
7 | model = Choice
8 | extra = 3
9 |
10 |
11 | class QuestionAdmin(admin.ModelAdmin):
12 | # fields = ['pub_date', 'question_text']
13 |
14 | fieldsets = [
15 | (None, {'fields': ['question_text']}),
16 | ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
17 | ]
18 |
19 | list_display = ('question_text', 'pub_date', 'was_published_recently')
20 | list_filter = ['pub_date']
21 | search_fields = ['question_text']
22 |
23 | admin.site.register(Question, QuestionAdmin)
24 | admin.site.register(Choice)
25 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/polls/models.py:
--------------------------------------------------------------------------------
1 | import datetime
2 |
3 | from django.db import models
4 | from django.utils import timezone
5 |
6 |
7 | class Question(models.Model):
8 | question_text = models.CharField(max_length=200)
9 | pub_date = models.DateTimeField('date published')
10 |
11 | def __str__(self):
12 | return self.question_text
13 |
14 | def was_puplished_recently(self):
15 | now = timezone.now()
16 | return now - datetime.timedelta(days=1) <= self.pub_date <= now
17 |
18 | was_puplished_recently.admin_order_field = 'pub_date'
19 | was_puplished_recently.boolean = True
20 | was_puplished_recently.short_description = 'Published recently?'
21 |
22 |
23 | class Choice(models.Model):
24 | question = models.ForeignKey(Question)
25 | choice_test = models.CharField(max_length=200)
26 | votes = models.IntegerField(default=0)
27 |
28 | def __str__(self):
29 | return self.choice_test
30 |
--------------------------------------------------------------------------------
/.idea/first_steps.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
25 |
26 |
--------------------------------------------------------------------------------
/polls/views.py:
--------------------------------------------------------------------------------
1 | from django.core.urlresolvers import reverse
2 | from django.http import HttpResponseRedirect
3 | from django.shortcuts import render, get_object_or_404
4 | from django.utils import timezone
5 | from django.views import generic
6 |
7 | from .models import Choice, Question
8 |
9 |
10 | class IndexView(generic.ListView):
11 | template_name = "polls/index.html"
12 | context_object_name = "latest_question_list"
13 |
14 | def get_queryset(self):
15 | return Question.objects.filter(
16 | pub_date__lte=timezone.now()
17 | ).order_by('-pub_date')[:5]
18 |
19 |
20 | class DetailView(generic.DetailView):
21 | model = Question
22 | template_name = "polls/detail.html"
23 |
24 | def get_queryset(self):
25 | """
26 | Excludes any questions that aren't published yet.
27 | """
28 | return Question.objects.filter(pub_date__lte=timezone.now())
29 |
30 |
31 | class ResultsView(generic.DetailView):
32 | model = Question
33 | template_name = "polls/results.html"
34 |
35 |
36 | def vote(request, question_id):
37 | p = get_object_or_404(Question, pk=question_id)
38 | try:
39 | selected_choice = p.choice_set.get(pk=request.POST['choice'])
40 | except (KeyError, Choice.DoesNotExist):
41 | return render(request, 'polls/detail.html', {
42 | 'question': p,
43 | 'error_message': "You didn't select a choice",
44 | })
45 | else:
46 | selected_choice.votes += 1
47 | selected_choice.save()
48 | return HttpResponseRedirect(reverse('polls:results', args=(p.id,)))
--------------------------------------------------------------------------------
/first_steps/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for first_steps project.
3 |
4 | For more information on this file, see
5 | https://docs.djangoproject.com/en/1.6/topics/settings/
6 |
7 | For the full list of settings and their values, see
8 | https://docs.djangoproject.com/en/1.6/ref/settings/
9 | """
10 |
11 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
12 | import os
13 | BASE_DIR = os.path.dirname(os.path.dirname(__file__))
14 |
15 |
16 | # Quick-start development settings - unsuitable for production
17 | # See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/
18 |
19 | # SECURITY WARNING: keep the secret key used in production secret!
20 | SECRET_KEY = 'hlq5ru(06+(ea@6kb+tl=7(oj3+f_!rk#$msygh^48a689nbte'
21 |
22 | # SECURITY WARNING: don't run with debug turned on in production!
23 | DEBUG = True
24 |
25 | TEMPLATE_DEBUG = True
26 |
27 | ALLOWED_HOSTS = []
28 |
29 |
30 | # Application definition
31 |
32 | INSTALLED_APPS = (
33 | 'django.contrib.admin',
34 | 'django.contrib.auth',
35 | 'django.contrib.contenttypes',
36 | 'django.contrib.sessions',
37 | 'django.contrib.messages',
38 | 'django.contrib.staticfiles',
39 | 'polls',
40 |
41 | )
42 |
43 | MIDDLEWARE_CLASSES = (
44 | 'django.contrib.sessions.middleware.SessionMiddleware',
45 | 'django.middleware.common.CommonMiddleware',
46 | 'django.middleware.csrf.CsrfViewMiddleware',
47 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
48 | 'django.contrib.messages.middleware.MessageMiddleware',
49 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
50 | )
51 |
52 | ROOT_URLCONF = 'first_steps.urls'
53 |
54 | WSGI_APPLICATION = 'first_steps.wsgi.application'
55 |
56 |
57 | # Database
58 | # https://docs.djangoproject.com/en/1.6/ref/settings/#databases
59 |
60 | DATABASES = {
61 | 'default': {
62 | 'ENGINE': 'django.db.backends.sqlite3',
63 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
64 | }
65 | }
66 |
67 | # Internationalization
68 | # https://docs.djangoproject.com/en/1.6/topics/i18n/
69 |
70 | LANGUAGE_CODE = 'en-us'
71 |
72 | TIME_ZONE = 'UTC'
73 |
74 | USE_I18N = True
75 |
76 | USE_L10N = True
77 |
78 | USE_TZ = True
79 |
80 |
81 | # Static files (CSS, JavaScript, Images)
82 | # https://docs.djangoproject.com/en/1.6/howto/static-files/
83 |
84 | STATIC_URL = '/static/'
85 |
86 | TEMPLATE_DIRS = (
87 | os.path.join(BASE_DIR, 'templates'),
88 | )
89 |
90 | TEMPLATES = [
91 | {
92 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
93 | 'DIRS': [os.path.join(BASE_DIR, 'templates')],
94 | 'APP_DIRS': True,
95 | 'OPTIONS': {
96 | 'context_processors': [
97 | 'django.template.context_processors.debug',
98 | 'django.template.context_processors.request',
99 | 'django.contrib.auth.context_processors.auth',
100 | 'django.contrib.messages.context_processors.messages',
101 | ],
102 | },
103 | },
104 | ]
--------------------------------------------------------------------------------
/polls/tests.py:
--------------------------------------------------------------------------------
1 | import datetime
2 | from django.core.urlresolvers import reverse
3 |
4 | from django.test import TestCase
5 | from django.utils import timezone
6 |
7 | from .models import Question
8 |
9 |
10 | def create_question(question_text, days):
11 | time = timezone.now() + datetime.timedelta(days=days)
12 | return Question.objects.create(question_text=question_text,
13 | pub_date=time)
14 |
15 |
16 | class QuestionViewTests(TestCase):
17 | def test_index_view_with_no_questions(self):
18 | """
19 | If no questions exist, an appropriate message should be displayed.
20 | """
21 | response = self.client.get(reverse('polls:index'))
22 | self.assertEqual(response.status_code, 200)
23 | self.assertContains(response, "No polls are available.")
24 | self.assertQuerysetEqual(response.context['latest_question_list'], [])
25 |
26 | def test_index_view_with_a_past_question(self):
27 | """
28 | Questions with a pub_date in the past should be displayed on the
29 | index page.
30 | """
31 | create_question(question_text="Past question.", days=-30)
32 | response = self.client.get(reverse('polls:index'))
33 | self.assertQuerysetEqual(
34 | response.context['latest_question_list'],
35 | ['']
36 | )
37 |
38 | def test_index_view_with_a_future_question(self):
39 | """
40 | Questions with a pub_date in the future should not be displayed on
41 | the index page.
42 | """
43 | create_question(question_text="Future question.", days=30)
44 | response = self.client.get(reverse('polls:index'))
45 | self.assertContains(response, "No polls are available.",
46 | status_code=200)
47 | self.assertQuerysetEqual(response.context['latest_question_list'], [])
48 |
49 | def test_index_view_with_future_question_and_past_question(self):
50 | """
51 | Even if both past and future questions exist, only past questions
52 | should be displayed.
53 | """
54 | create_question(question_text="Past question.", days=-30)
55 | create_question(question_text="Future question.", days=30)
56 | response = self.client.get(reverse('polls:index'))
57 | self.assertQuerysetEqual(
58 | response.context['latest_question_list'],
59 | ['']
60 | )
61 |
62 | def test_index_view_with_two_past_questions(self):
63 | """
64 | The questions index page may display multiple questions.
65 | """
66 | create_question(question_text="Past question 1.", days=-30)
67 | create_question(question_text="Past question 2.", days=-5)
68 | response = self.client.get(reverse('polls:index'))
69 | self.assertQuerysetEqual(
70 | response.context['latest_question_list'],
71 | ['', '']
72 | )
73 |
74 |
75 | class QuestionIndexDetailTests(TestCase):
76 | def test_detail_view_with_a_future_question(self):
77 | """
78 | The detail view of a question with a pub_date in the future should
79 | return a 404 not found.
80 | """
81 | future_question = create_question(question_text='Future question.',
82 | days=5)
83 | response = self.client.get(reverse('polls:detail',
84 | args=(future_question.id,)))
85 | self.assertEqual(response.status_code, 404)
86 |
87 | def test_detail_view_with_a_past_question(self):
88 | """
89 | The detail view of a question with a pub_date in the past should
90 | display the question's text.
91 | """
92 | past_question = create_question(question_text='Past Question.',
93 | days=-5)
94 | response = self.client.get(reverse('polls:detail',
95 | args=(past_question.id,)))
96 | self.assertContains(response, past_question.question_text,
97 | status_code=200)
--------------------------------------------------------------------------------
/playing_with_API.py:
--------------------------------------------------------------------------------
1 | from polls.models import Question, Choice # Import the model classes we just wrote.
2 |
3 |
4 | Question.objects.all()
5 |
6 | # Create a new Question.
7 | # Support for time zones is enabled in the default settings file, so
8 | # Django expects a datetime with tzinfo for pub_date. Use timezone.now()
9 | # instead of datetime.datetime.now() and it will do the right thing.
10 | from django.utils import timezone
11 | q = Question(question_text="What's new?", pub_date=timezone.now())
12 |
13 | # Save the object into the database. You have to call save() explicitly.
14 | q.save()
15 |
16 | # Now it has an ID. Note that this might say "1L" instead of "1", depending
17 | # on which database you're using. That's no biggie; it just means your
18 | # database backend prefers to return integers as Python long integer
19 | # objects.
20 | print(q.id)
21 |
22 |
23 | # Access model field values via Python attributes.
24 | print(q.question_text)
25 | print(q.pub_date)
26 |
27 | # Change values by changing the attributes, then calling save().
28 | q.question_text = "What's up?"
29 | q.save()
30 |
31 | Question.objects.all()
32 | Question.objects.filter(id=1)
33 | Question.objects.filter(question_text__startswith='What')
34 |
35 | # Get the question that was published this year.
36 | from django.utils import timezone
37 | current_year = timezone.now().year
38 | Question.objects.get(pub_date__year=current_year)
39 |
40 | # Request an ID that doesn't exist, this will raise an exception.
41 | Question.objects.get(id=2)
42 |
43 | # Lookup by a primary key is the most common case, so Django provides a
44 | # shortcut for primary-key exact lookups.
45 | # The following is identical to Question.objects.get(id=1).
46 | Question.objects.get(pk=1)
47 |
48 | # Make sure our custom method worked.
49 | q = Question.objects.get(pk=1)
50 | q.was_published_recently()
51 |
52 | # Give the Question a couple of Choices. The create call constructs a new
53 | # Choice object, does the INSERT statement, adds the choice to the set
54 | # of available choices and returns the new Choice object. Django creates
55 | # a set to hold the "other side" of a ForeignKey relation
56 | # (e.g. a question's choice) which can be accessed via the API.
57 | q = Question.objects.get(pk=1)
58 |
59 | # Display any choices from the related object set -- none so far.
60 | q.choice_set.all()
61 |
62 | # Create three choices.
63 | q.choice_set.create(choice_text='Not much', votes=0)
64 | q.choice_set.create(choice_text='The sky', votes=0)
65 | c = q.choice_set.create(choice_text='Just hacking again', votes=0)
66 |
67 | # Choice objects have API access to their related Question objects.
68 | print(c.question)
69 |
70 | # And vice versa: Question objects get access to Choice objects.
71 | q.choice_set.all()
72 | q.choice_set.count()
73 |
74 | # The API automatically follows relationships as far as you need.
75 | # Use double underscores to separate relationships.
76 | # This works as many levels deep as you want; there's no limit.
77 | # Find all Choices for any question whose pub_date is in this year
78 | # (reusing the 'current_year' variable we created above).
79 | Choice.objects.filter(question__pub_date__year=current_year)
80 |
81 | # Let's delete one of the choices. Use delete() for that.
82 | c = q.choice_set.filter(choice_text__startswith='Just hacking')
83 | c.delete()
84 |
85 | import datetime
86 | from django.utils import timezone
87 | from polls.models import Question
88 | # create a Question instance with pub_date 30 days in the future
89 | future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30))
90 | # was it published recently?
91 | future_question.was_published_recently()
92 |
93 |
94 | from django.test.utils import setup_test_environment
95 | setup_test_environment()
96 |
97 | from django.test import Client
98 | # create an instance of the client for our use
99 | client = Client()
100 |
101 | # get a response from '/'
102 | response = client.get('/')
103 | # we should expect a 404 from that address
104 | print(response.status_code)
105 | # on the other hand we should expect to find something at '/polls/'
106 | # we'll use 'reverse()' rather than a hardcoded URL
107 | from django.core.urlresolvers import reverse
108 | response = client.get(reverse('polls:index'))
109 | print(response.status_code)
110 | print(response.content)
111 | # note - you might get unexpected results if your ``TIME_ZONE``
112 | # in ``settings.py`` is not correct. If you need to change it,
113 | # you will also need to restart your shell session
114 | from polls.models import Question
115 | from django.utils import timezone
116 | # create a Question and save it
117 | q = Question(question_text="Who is your favorite Beatle?", pub_date=timezone.now())
118 | q.save()
119 | # check the response once again
120 | response = client.get('/polls/')
121 | print(response.content)
122 | # If the following doesn't work, you probably omitted the call to
123 | # setup_test_environment() described above
124 | print(response.context['latest_question_list'])
125 |
--------------------------------------------------------------------------------