Last active
March 6, 2025 05:55
-
-
Save RajaniCode/f61a7e896ee182c21c2450ddc17ccf02 to your computer and use it in GitHub Desktop.
Python Django
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
########################################################################################################################### | |
# Python # Django | |
########################################################################################################################### | |
*************************************************************************************************************************** | |
# Django | |
*************************************************************************************************************************** | |
% python3 --version | |
% pip3 --version | |
% pip --version | |
% python3 -m pip install --upgrade pip | |
% pip list | |
% pip freeze | |
% pip show pip | |
% pip show setuptools | |
[ | |
% pip install django | |
] | |
% python3 -m pip install django | |
% python3 -m django --version | |
% django-admin --version | |
% python3 -c "import django; print(django.__version__)" 3.2.9 | |
*************************************************************************************************************************** | |
# Django # Project | |
*************************************************************************************************************************** | |
% mkdir -p djangoproject | |
% django-admin startproject djangosite djangoproject | |
% cd djangoproject | |
% tree | |
[ | |
. | |
├── djangosite | |
│ ├── __init__.py | |
│ ├── asgi.py | |
│ ├── settings.py | |
│ ├── urls.py | |
│ └── wsgi.py | |
└── manage.py | |
2 directories, 6 files | |
] | |
*************************************************************************************************************************** | |
# Django Development Server | |
*************************************************************************************************************************** | |
% python3 manage.py runserver | |
# Terminal Window # curl # open | |
% curl http://127.0.0.1:8000/ | |
% open http://127.0.0.1:8000/ | |
*************************************************************************************************************************** | |
# Django # Polls # App | |
*************************************************************************************************************************** | |
# Original Terminal Window | |
<control + c> | |
% python3 manage.py startapp polls | |
% tree polls | |
[ | |
polls | |
├── __init__.py | |
├── admin.py | |
├── apps.py | |
├── migrations | |
│ └── __init__.py | |
├── models.py | |
├── tests.py | |
└── views.py | |
2 directories, 7 files | |
] | |
=========================================================================================================================== | |
# Django # Views | |
=========================================================================================================================== | |
--------------------------------------------------------------------------------------------------------------------------- | |
# polls/views.py | |
--------------------------------------------------------------------------------------------------------------------------- | |
# Edit | |
% nano polls/views.py | |
[ | |
# import sys | |
# import django | |
from django.http import HttpResponse | |
# 'Python: ' + sys.version + ' Django: ' + str(django.VERSION).strip('(').strip(')') | |
# 'Python: ' + __import__("sys").version + ' Django: ' + str(__import__("django").VERSION).strip('(').strip(')') | |
def index(request): | |
# return HttpResponse('This is polls index. Python: ' + sys.version + ' Django: ' + django.get_version()) | |
return HttpResponse('This is polls index. Python: ' + __import__("sys").version + ' Django: ' + __import__("django").get_version()) | |
] | |
% cat polls/views.py | |
--------------------------------------------------------------------------------------------------------------------------- | |
# polls/urls.py | |
--------------------------------------------------------------------------------------------------------------------------- | |
# Create | |
% nano polls/urls.py | |
[ | |
from django.urls import path | |
from . import views | |
urlpatterns = [ | |
path("", views.index, name="index"), | |
] | |
] | |
% cat polls/urls.py | |
% tree polls | |
[ | |
polls | |
├── __init__.py | |
├── admin.py | |
├── apps.py | |
├── migrations | |
│ └── __init__.py | |
├── models.py | |
├── tests.py | |
├── urls.py | |
└── views.py | |
2 directories, 8 files | |
] | |
--------------------------------------------------------------------------------------------------------------------------- | |
# djangosite/views.py | |
--------------------------------------------------------------------------------------------------------------------------- | |
# Add | |
% nano djangosite/views.py | |
[ | |
# import sys | |
# import django | |
from django.http import HttpResponse | |
def index(request): | |
# return HttpResponse('This is root index. Python: ' + sys.version + ' Django: ' + django.get_version()) | |
return HttpResponse('This is root index. Python: ' + __import__("sys").version + ' Django: ' + __import__("django").get_version()) | |
] | |
% cat djangosite/views.py | |
--------------------------------------------------------------------------------------------------------------------------- | |
# djangosite/urls.py | |
--------------------------------------------------------------------------------------------------------------------------- | |
# Edit | |
% nano djangosite/urls.py | |
[ | |
from django.contrib import admin | |
from django.urls import include, path | |
from . import views | |
urlpatterns = [ | |
path("", views.index, name="index"), | |
path('polls/', include('polls.urls')), | |
path('admin/', admin.site.urls), | |
] | |
] | |
% cat djangosite/urls.py | |
% python3 manage.py runserver | |
# Terminal Window # curl # open | |
% curl http://localhost:8000/ | |
% open http://localhost:8000/ | |
% curl http://localhost:8000/polls/ | |
% open http://localhost:8000/polls/ | |
% curl http://localhost:8000/admin/ | |
[ | |
% curl -L http://127.0.0.1:8000/admin/ | |
] | |
% open http://localhost:8000/admin/ | |
--------------------------------------------------------------------------------------------------------------------------- | |
=========================================================================================================================== | |
*************************************************************************************************************************** | |
# Django # Database # Setup # Migration # migrate | |
*************************************************************************************************************************** | |
# By default, INSTALLED_APPS contains the following apps, all of which come with Django. | |
# django.contrib.admin – The admin site. | |
# django.contrib.auth – An authentication system. | |
# django.contrib.contenttypes – A framework for content types. | |
# django.contrib.sessions – A session framework. | |
# django.contrib.messages – A messaging framework. | |
# django.contrib.staticfiles – A framework for managing static files. | |
# Original Terminal Window | |
<control + c> | |
% python3 manage.py migrate | |
[ | |
Operations to perform: | |
Apply all migrations: admin, auth, contenttypes, sessions | |
Running migrations: | |
Applying contenttypes.0001_initial... OK | |
Applying auth.0001_initial... OK | |
Applying admin.0001_initial... OK | |
Applying admin.0002_logentry_remove_auto_add... OK | |
Applying admin.0003_logentry_add_action_flag_choices... OK | |
Applying contenttypes.0002_remove_content_type_name... OK | |
Applying auth.0002_alter_permission_name_max_length... OK | |
Applying auth.0003_alter_user_email_max_length... OK | |
Applying auth.0004_alter_user_username_opts... OK | |
Applying auth.0005_alter_user_last_login_null... OK | |
Applying auth.0006_require_contenttypes_0002... OK | |
Applying auth.0007_alter_validators_add_error_messages... OK | |
Applying auth.0008_alter_user_username_max_length... OK | |
Applying auth.0009_alter_user_last_name_max_length... OK | |
Applying auth.0010_alter_group_name_max_length... OK | |
Applying auth.0011_update_proxy_permissions... OK | |
Applying auth.0012_alter_user_first_name_max_length... OK | |
Applying sessions.0001_initial... OK | |
] | |
*************************************************************************************************************************** | |
# Django # Models # Question # Choice | |
*************************************************************************************************************************** | |
# Edit | |
% nano polls/models.py | |
[ | |
import datetime | |
from django.db import models | |
from django.utils import timezone | |
from django.contrib import admin | |
class Question(models.Model): | |
question_text = models.CharField(max_length=200) | |
pub_date = models.DateTimeField('date published') | |
def __str__(self): | |
return self.question_text | |
@admin.display( | |
boolean=True, | |
ordering='pub_date', | |
description='Published recently?', | |
) | |
def was_published_recently(self): | |
now = timezone.now() | |
return now - datetime.timedelta(days=1) <= self.pub_date <= now | |
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 | |
] | |
% cat polls/models.py | |
*************************************************************************************************************************** | |
# Django # Activating Models # Migration # makemigrations # sqlmigrate # migrate | |
*************************************************************************************************************************** | |
=========================================================================================================================== | |
# Edit # Add # 'polls.apps.PollsConfig', | |
% nano djangosite/settings.py | |
[ | |
... | |
INSTALLED_APPS = [ | |
'polls.apps.PollsConfig', | |
'django.contrib.admin', | |
'django.contrib.auth', | |
'django.contrib.contenttypes', | |
'django.contrib.sessions', | |
'django.contrib.messages', | |
'django.contrib.staticfiles', | |
] | |
... | |
] | |
% cat djangosite/settings.py | |
% python3 manage.py makemigrations polls | |
[ | |
Migrations for 'polls': | |
polls/migrations/0001_initial.py | |
- Create model Question | |
- Create model Choice | |
] | |
=========================================================================================================================== | |
% python3 manage.py sqlmigrate polls 0001 | |
[ | |
Migrations for 'polls': | |
polls/migrations/0001_initial.py | |
- Create model Question | |
- Create model Choice | |
rajaniapple@Rajanis-MacBook-Pro djangoproject % python3 manage.py sqlmigrate polls 0001 | |
BEGIN; | |
-- | |
-- Create model Question | |
-- | |
CREATE TABLE "polls_question" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "question_text" varchar(200) NOT NULL, "pub_date" datetime NOT NULL); | |
-- | |
-- Create model Choice | |
-- | |
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL, "question_id" bigint NOT NULL REFERENCES "polls_question" ("id") DEFERRABLE INITIALLY DEFERRED); | |
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id"); | |
COMMIT; | |
] | |
=========================================================================================================================== | |
% python3 manage.py migrate | |
[ | |
Operations to perform: | |
Apply all migrations: admin, auth, contenttypes, polls, sessions | |
Running migrations: | |
Applying polls.0001_initial... OK | |
] | |
=========================================================================================================================== | |
*************************************************************************************************************************** | |
# Django # Shell | |
*************************************************************************************************************************** | |
% python3 manage.py shell | |
>>> __import__("sys").version | |
>>> __import__("django").VERSION | |
>>> __import__("django").get_version() | |
>>> from polls.models import Choice, Question | |
>>> Question.objects.all() | |
>>> from django.utils import timezone | |
>>> q = Question(question_text="What's new?", pub_date=timezone.now()) | |
>>> q.save() | |
>>> q.id | |
>>> q.question_text | |
>>> q.pub_date | |
>>> q.question_text = "What's up?" | |
>>> q.save() | |
>>> Question.objects.all() | |
>>> Question.objects.filter(id=1) | |
>>> current_year = timezone.now().year | |
>>> Question.objects.get(pub_date__year=current_year) | |
>>> Question.objects.get(pk=1) | |
>>> q = Question.objects.get(pk=1) | |
>>> q.was_published_recently() | |
>>> q = Question.objects.get(pk=1) | |
>>> q.choice_set.all() | |
>>> q.choice_set.create(choice_text="Python", votes=0) | |
>>> q.choice_set.create(choice_text="Django", votes=0) | |
>>> c = q.choice_set.create(choice_text="Flask", votes=0) | |
>>> c.question | |
>>> q.choice_set.all() | |
>>> q.choice_set.count() | |
>>> Choice.objects.filter(question__pub_date__year=current_year) | |
>>> c = q.choice_set.filter(choice_text__startswith="Flask") | |
>>> c.delete() | |
>>> Choice.objects.all() | |
>>> Question.objects.all() | |
>>> exit() | |
*************************************************************************************************************************** | |
# Django # Views | |
*************************************************************************************************************************** | |
=========================================================================================================================== | |
# polls/views.py | |
=========================================================================================================================== | |
% nano polls/views.py | |
[ | |
from django.http import HttpResponseRedirect | |
from django.shortcuts import get_object_or_404, render | |
from django.urls import reverse | |
from django.views import generic | |
from django.utils import timezone | |
from .models import Choice, Question | |
class IndexView(generic.ListView): | |
template_name = 'polls/index.html' | |
context_object_name = 'latest_question_list' | |
def get_queryset(self): | |
""" | |
Return the last five published questions (not including those set to be | |
published in the future). | |
""" | |
return Question.objects.filter( | |
pub_date__lte=timezone.now() | |
).order_by('-pub_date')[:5] | |
class DetailView(generic.DetailView): | |
model = Question | |
template_name = 'polls/detail.html' | |
def get_queryset(self): | |
""" | |
Excludes any questions that aren't published yet. | |
""" | |
return Question.objects.filter(pub_date__lte=timezone.now()) | |
class ResultsView(generic.DetailView): | |
model = Question | |
template_name = 'polls/results.html' | |
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 += 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,))) | |
] | |
% cat polls/views.py | |
=========================================================================================================================== | |
# polls/urls.py | |
=========================================================================================================================== | |
% nano polls/urls.py | |
[ | |
from django.urls import path | |
from . import views | |
app_name = 'polls' | |
urlpatterns = [ | |
path('', views.IndexView.as_view(), name='index'), | |
path('<int:pk>/', views.DetailView.as_view(), name='detail'), | |
path('<int:pk>/results/', views.ResultsView.as_view(), name='results'), | |
path('<int:question_id>/vote/', views.vote, name='vote'), | |
] | |
] | |
% cat polls/urls.py | |
=========================================================================================================================== | |
*************************************************************************************************************************** | |
# Django # Templates | |
*************************************************************************************************************************** | |
[ | |
% mkdir -p polls/static/polls/images | |
] | |
# --create-dirs --output-dir | |
% curl --output background.gif "https://avatars.githubusercontent.com/u/27804?s=200&v=4" --create-dirs --output-dir polls/static/polls/images | |
% ls polls/static/polls/images/background.gif | |
% open polls/static/polls/images/background.gif | |
% nano polls/static/polls/style.css | |
[ | |
li a { | |
color: green; | |
} | |
body { | |
background: white url("images/background.gif") no-repeat right bottom; | |
} | |
] | |
% cat polls/static/polls/style.css | |
% mkdir -p polls/templatetags | |
% nano polls/templatetags/version_tags.py | |
[ | |
# import sys | |
# import django | |
from django import template | |
register = template.Library() | |
@register.simple_tag | |
def version_string(): | |
# return 'This is polls index. Python: ' + sys.version + ' Django: ' + django.get_version() | |
return 'This is polls index. Python: ' + __import__("sys").version + ' Django: ' + __import__("django").get_version() | |
] | |
% cat polls/templatetags/version_tags.py | |
% mkdir -p polls/templates/polls | |
# NB | |
# Warning | |
# The {% static %} template tag is not available for use in static files which aren't generated by Django, like the stylesheet. | |
# Always use relative paths to link the static files between each other to change STATIC_URL (used by the static template tag to generate its URLs) without having to modify a bunch of paths in the static files as well. | |
% nano polls/templates/polls/index.html | |
[ | |
{% load static %} | |
{% load version_tags %} | |
{% version_string %} | |
<link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}"> | |
{% if latest_question_list %} | |
<ul> | |
{% for question in latest_question_list %} | |
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li> | |
{% endfor %} | |
</ul> | |
{% else %} | |
<p>No polls are available.</p> | |
{% endif %} | |
] | |
% cat polls/templates/polls/index.html | |
% nano polls/templates/polls/detail.html | |
[ | |
<form action="{% url 'polls:vote' question.id %}" method="post"> | |
{% csrf_token %} | |
<fieldset> | |
<legend><h1>{{ question.question_text }}</h1></legend> | |
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} | |
{% for choice in question.choice_set.all %} | |
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}"> | |
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br> | |
{% endfor %} | |
</fieldset> | |
<input type="submit" value="Vote"> | |
</form> | |
] | |
% cat polls/templates/polls/detail.html | |
% nano polls/templates/polls/results.html | |
[ | |
<h1>{{ question.question_text }}</h1> | |
<ul> | |
{% for choice in question.choice_set.all %} | |
<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li> | |
{% endfor %} | |
</ul> | |
<a href="{% url 'polls:detail' question.id %}">Vote again?</a> | |
] | |
% cat polls/templates/polls/results.html | |
*************************************************************************************************************************** | |
=========================================================================================================================== | |
# djangosite/views.py | |
=========================================================================================================================== | |
% nano djangosite/views.py | |
[ | |
from django.http import HttpResponseRedirect | |
def index(request): | |
return HttpResponseRedirect('polls') | |
] | |
% cat djangosite/views.py | |
=========================================================================================================================== | |
# djangosite/urls.py | |
=========================================================================================================================== | |
% cat djangosite/urls.py | |
[ | |
from django.contrib import admin | |
from django.urls import include, path | |
from . import views | |
urlpatterns = [ | |
path("", views.index, name="index"), | |
path('polls/', include('polls.urls')), | |
path('admin/', admin.site.urls), | |
] | |
] | |
% python3 manage.py runserver | |
# Terminal Window # curl # open | |
[ | |
% curl http://localhost:8000/ | |
] | |
% curl -L http://localhost:8000/ | |
% open http://localhost:8000/ | |
% curl http://localhost:8000/polls/ | |
% open http://localhost:8000/polls/ | |
=========================================================================================================================== | |
*************************************************************************************************************************** | |
*************************************************************************************************************************** | |
# Django # Admin # createsuperuser | |
*************************************************************************************************************************** | |
# Original Terminal Window | |
<control + c> | |
% python3 manage.py createsuperuser | |
[ | |
Enter your desired username and press enter. | |
Username: admin | |
You will then be prompted for your desired email address: | |
Email address: [email protected] | |
The final step is to enter your password. You will be asked to enter your password twice, the second time as a confirmation of the first. | |
Password: *********** | |
Password (again): *********** | |
Superuser created successfully. | |
] | |
% python3 manage.py runserver | |
# Terminal Window # curl # open | |
[ | |
% curl http://127.0.0.1:8000/admin/ | |
] | |
% curl -L http://127.0.0.1:8000/admin/ | |
% open http://127.0.0.1:8000/admin/ | |
*************************************************************************************************************************** | |
# Django # Shell # Admin | |
*************************************************************************************************************************** | |
=========================================================================================================================== | |
# Original Terminal Window | |
<control + c> | |
% python3 manage.py shell | |
>>> __import__("sys").version | |
>>> __import__("django").VERSION | |
>>> __import__("django").get_version() | |
>>> from django.contrib.auth.models import User | |
>>> users = User.objects.all() | |
>>> users | |
<QuerySet [<User: admin>]> | |
>>> user = users[0] | |
>>> user.set_password('***********') | |
>>> user.save() | |
>>> exit() | |
=========================================================================================================================== | |
% python3 manage.py shell | |
>>> __import__("sys").version | |
>>> __import__("django").VERSION | |
>>> __import__("django").get_version() | |
>>> from django.contrib.auth.models import User | |
>>> users = User.objects.all() | |
>>> users | |
>>> user = User.objects.create_user('superguest', password='************'); | |
>>> user.is_superuser=True | |
>>> user.save() | |
>>> users | |
>>> user = users[1] | |
>>> user | |
>>> user.delete() | |
>>> users | |
>>> exit() | |
=========================================================================================================================== | |
*************************************************************************************************************************** | |
# Django # Admin # Polls | |
*************************************************************************************************************************** | |
# Make the poll app modifiable in the admin | |
% nano polls/admin.py | |
[ | |
from django.contrib import admin | |
from .models import Choice, Question | |
class ChoiceInline(admin.TabularInline): | |
model = Choice | |
extra = 3 | |
class QuestionAdmin(admin.ModelAdmin): | |
fieldsets = [ | |
(None, {'fields': ['question_text']}), | |
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}), | |
] | |
inlines = [ChoiceInline] | |
list_display = ('question_text', 'pub_date', 'was_published_recently') | |
list_filter = ['pub_date'] | |
search_fields = ['question_text'] | |
admin.site.register(Question, QuestionAdmin) | |
] | |
% cat polls/admin.py | |
*************************************************************************************************************************** | |
# Django # Admin # Polls # base_site.html | |
*************************************************************************************************************************** | |
% mkdir -p polls/templates/admin | |
% nano polls/templates/admin/base_site.html | |
[ | |
{% extends "admin/base.html" %} | |
{% block title %}{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %} | |
{% block branding %} | |
<h1 id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></h1> | |
{% endblock %} | |
{% block nav-global %}{% endblock %} | |
] | |
% cat polls/templates/admin/base_site.html | |
# Templates can live anywhere on your filesystem that Django can access. | |
# (Django runs as whatever user your server runs.) | |
# However, keeping your templates within the project is a good convention. | |
% nano djangosite/settings.py | |
[ | |
... | |
TEMPLATES = [ | |
{ | |
'BACKEND': 'django.template.backends.django.DjangoTemplates', | |
'DIRS': [BASE_DIR / 'templates'], | |
'APP_DIRS': True, | |
'OPTIONS': { | |
'context_processors': [ | |
'django.template.context_processors.debug', | |
'django.template.context_processors.request', | |
'django.contrib.auth.context_processors.auth', | |
'django.contrib.messages.context_processors.messages', | |
], | |
}, | |
}, | |
] | |
... | |
] | |
% cat djangosite/settings.py | |
% python3 manage.py runserver | |
# Terminal Window # curl # open | |
[ | |
% curl http://localhost:8000/admin/ | |
] | |
% curl -L http://localhost:8000/admin/ | |
% open http://localhost:8000/admin/ | |
% curl http://localhost:8000/ | |
[ | |
% curl -L http://localhost:8000/ | |
] | |
% curl http://localhost:8000/polls/ | |
% open http://localhost:8000/polls/ | |
*************************************************************************************************************************** | |
# Django # Test | |
*************************************************************************************************************************** | |
# Original Terminal Window | |
<control + c> | |
% nano polls/tests.py | |
[ | |
import datetime | |
from django.test import TestCase | |
from django.utils import timezone | |
from django.urls import reverse | |
from .models import Question | |
class QuestionModelTests(TestCase): | |
def test_was_published_recently_with_future_question(self): | |
""" | |
was_published_recently() returns False for questions whose pub_date | |
is in the future. | |
""" | |
time = timezone.now() + datetime.timedelta(days=30) | |
future_question = Question(pub_date=time) | |
self.assertIs(future_question.was_published_recently(), False) | |
def test_was_published_recently_with_old_question(self): | |
""" | |
was_published_recently() returns False for questions whose pub_date | |
is older than 1 day. | |
""" | |
time = timezone.now() - datetime.timedelta(days=1, seconds=1) | |
old_question = Question(pub_date=time) | |
self.assertIs(old_question.was_published_recently(), False) | |
def test_was_published_recently_with_recent_question(self): | |
""" | |
was_published_recently() returns True for questions whose pub_date | |
is within the last day. | |
""" | |
time = timezone.now() - datetime.timedelta(hours=23, minutes=59, seconds=59) | |
recent_question = Question(pub_date=time) | |
self.assertIs(recent_question.was_published_recently(), True) | |
def create_question(question_text, days): | |
""" | |
Create a question with the given `question_text` and published the | |
given number of `days` offset to now (negative for questions published | |
in the past, positive for questions that have yet to be published). | |
""" | |
time = timezone.now() + datetime.timedelta(days=days) | |
return Question.objects.create(question_text=question_text, pub_date=time) | |
class QuestionIndexViewTests(TestCase): | |
def test_no_questions(self): | |
""" | |
If no questions exist, an appropriate message is displayed. | |
""" | |
response = self.client.get(reverse('polls:index')) | |
self.assertEqual(response.status_code, 200) | |
self.assertContains(response, "No polls are available.") | |
self.assertQuerysetEqual(response.context['latest_question_list'], []) | |
def test_past_question(self): | |
""" | |
Questions with a pub_date in the past are displayed on the | |
index page. | |
""" | |
question = create_question(question_text="Past question.", days=-30) | |
response = self.client.get(reverse('polls:index')) | |
self.assertQuerysetEqual( | |
response.context['latest_question_list'], | |
[question], | |
) | |
def test_future_question(self): | |
""" | |
Questions with a pub_date in the future aren't displayed on | |
the index page. | |
""" | |
create_question(question_text="Future question.", days=30) | |
response = self.client.get(reverse('polls:index')) | |
self.assertContains(response, "No polls are available.") | |
self.assertQuerysetEqual(response.context['latest_question_list'], []) | |
def test_future_question_and_past_question(self): | |
""" | |
Even if both past and future questions exist, only past questions | |
are displayed. | |
""" | |
question = create_question(question_text="Past question.", days=-30) | |
create_question(question_text="Future question.", days=30) | |
response = self.client.get(reverse('polls:index')) | |
self.assertQuerysetEqual( | |
response.context['latest_question_list'], | |
[question], | |
) | |
def test_two_past_questions(self): | |
""" | |
The questions index page may display multiple questions. | |
""" | |
question1 = create_question(question_text="Past question 1.", days=-30) | |
question2 = create_question(question_text="Past question 2.", days=-5) | |
response = self.client.get(reverse('polls:index')) | |
self.assertQuerysetEqual( | |
response.context['latest_question_list'], | |
[question2, question1], | |
) | |
class QuestionDetailViewTests(TestCase): | |
def test_future_question(self): | |
""" | |
The detail view of a question with a pub_date in the future | |
returns a 404 not found. | |
""" | |
future_question = create_question(question_text='Future question.', days=5) | |
url = reverse('polls:detail', args=(future_question.id,)) | |
response = self.client.get(url) | |
self.assertEqual(response.status_code, 404) | |
def test_past_question(self): | |
""" | |
The detail view of a question with a pub_date in the past | |
displays the question's text. | |
""" | |
past_question = create_question(question_text='Past Question.', days=-5) | |
url = reverse('polls:detail', args=(past_question.id,)) | |
response = self.client.get(url) | |
self.assertContains(response, past_question.question_text) | |
] | |
% cat polls/tests.py | |
% touch polls/__init__.py | |
% ls polls/__init__.py | |
% cat polls/__init__.py | |
# Run the tests | |
% python3 manage.py test polls | |
*************************************************************************************************************************** | |
# Django # Shell # Tests # Confirm | |
*************************************************************************************************************************** | |
# Three tests that confirm that Question.was_published_recently() returns sensible values for past, recent, and future questions. | |
% python3 manage.py shell | |
>>> import datetime | |
>>> from django.utils import timezone | |
>>> from polls.models import Question | |
>>> future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30)) | |
>>> future_question.was_published_recently() | |
>>> old_question = Question(pub_date=timezone.now() - datetime.timedelta(days=360)) | |
>>> old_question.was_published_recently() | |
>>> recent_question = Question(pub_date=timezone.now() + datetime.timedelta(days=0)) | |
>>> recent_question.was_published_recently() | |
>>> exit() | |
*************************************************************************************************************************** | |
# Django # Shell # Test # client | |
*************************************************************************************************************************** | |
% python3 manage.py shell | |
>>> from django.test.utils import setup_test_environment | |
>>> setup_test_environment() | |
>>> from django.test import Client | |
>>> client = Client() | |
>>> response = client.get('/') | |
>>> response.status_code | |
>>> response = client.get('/index') | |
>>> response.status_code | |
>>> response = client.get('/polls') | |
>>> response.status_code | |
>>> response = client.get('/admin') | |
>>> response.status_code | |
>>> response = client.get('') | |
>>> response.status_code | |
>>> from django.urls import reverse | |
>>> response = client.get(reverse('polls:index')) | |
>>> response.status_code | |
>>> response.content | |
>>> response.context['latest_question_list'] | |
>>> exit() | |
*************************************************************************************************************************** | |
########################################################################################################################### | |
// Credits | |
/* | |
https://djangoproject.com/ | |
https://python.org/ | |
https://pypi.org/ | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment