Official tutorial for Django, the python web framework "Creating your first Django app" Notes 1-5.
It's really just a memo.
Click here for the original website https://docs.djangoproject.com/ja/3.1/intro/tutorial01/
Create a python environment and enter with pip
terminal
pip install django
I will check if it is included
terminal
$ python -m django --version
3.1.2
It seems that django 3.1.2 is included
When you run django-admin startproject hoge, it will automatically create the minimum required folders and files for your project.
terminal
django-admin startproject mysite
The created file has the following structure
Directory structure
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
DB is python standard sqlite3.
For the time being, the sample page can be displayed in this state, so let's try it. Running manage.py runserver will start a simple server for development.
terminal
python manage.py runserver
Since the started server waits on port 8000 of local host, you can see that you can open the following URL with a browser. http://127.0.0.1:8000
In addition, since this simple server is made only for use during development, it is written in the official tutorial that "Never use it in a production environment". In the production environment, let's publish using Apache etc.
Django allows you to work with multiple applications. If you execute as follows, the minimum required files for the application will be automatically generated.
terminal
python manage.py startapp polls
Directory structure
polls/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
views.py
You can create as many apps as you like, so it seems that productivity will increase if you divide them well by function.
view is written in views.py.
The following is a view that returns "Hello, world. You're at the polls index." On http when you come to read /polls/index.html.
polls/views.py
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world. You're at the polls index.")
I will write the association to the above views.py in urls.py.
Write it in django.urls.path () and it will be associated. If you write as follows, you will find index () in polls / views.py by referring to mysite / urls.py → polls / urls.py → polls / views.py in that order.
mysite/urls.py
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('polls/', include('polls.urls')),
path('admin/', admin.site.urls),
]
polls/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
Now that the association is complete, let's start the simple server and check it.
terminal
python manage.py runserver
The contents written in polls / views.py will wait for you in the url. http://localhost:8000/polls/
By default, sqlite3 is used, so you can do it without setting DB. I think that it will be changed to postgreSQL or mySQL in production, so in that case refer to the following. https://docs.djangoproject.com/ja/3.1/intro/tutorial02/
The standard is set in UTC
mysite/setting.Before changing py
TIME_ZONE = 'UTC'
If you want to use Japan Standard Time, change as follows
mysite/setting.After changing py
TIME_ZONE = 'Asia/Tokyo'
USE_TZ = True
Build a DB based on the contents of setting.py
terminal
python manage.py migrate
Since django treats DB data as an object, it seems that data handling will be easier. (I'm not sure at this point.)
polls/models.py
import datetime
from django.db import models
from django.utils import timezone
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
setting.py
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
Make django aware that the model has changed
terminal
python manage.py makemigrations polls
Although django is designed to be more productive by forcing a tidy directory structure, it has the problem of complicated file connections and the difficulty of seeing what happens when you run a function from django. The django shell is provided to help you check this, and you can run it in the python manage.py shell.
django_shell
>>> from polls.models import Choice, Question
>>> Question.objects.all()
<QuerySet []>
django_shell
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())
>>> q.save()
django_shell
>>> q.id
1
django_shell
>>> q.question_text = "What's up?"
>>> q.save()
django_shell
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>]>
django_shell
>>> q.question_text
>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)
django_shell
python manage.py shell
In [1]:
django_shell
>>> from polls.models import Choice, Question
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]>
django_shell
>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>
django_shell
>>> Question.objects.filter(question_text__startswith='What')
<QuerySet [<Question: What's up?>]>
django_shell
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>
django_shell
>>> Question.objects.get(id=2)
Traceback (most recent call last):
...
DoesNotExist: Question matching query does not exist.
django_shell
>>> Question.objects.get(pk=1)
<Question: What's up?>
django_shell
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True
django_shell
>>> q = Question.objects.get(pk=1)
>>> q.choice_set.all()
<QuerySet []>
django_shell
>>> q.choice_set.create(choice_text='Not much', votes=0)
>>> q.choice_set.create(choice_text='The sky', votes=0)
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)
>>> c.question
<Question: What's up?>
django_shell
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
django_shell
>>> q.choice_set.count()
3
django_shell
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
django_shell
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()
Create a superuser for django project supervision. This superuser is for django, so it's separate from the Linux OS user.
django_shell
python manage.py createsuperuser
Enter your ID and password to complete the registration. This will allow you to log in to the admin page, so start the simple server and log in to the admin page.
django_shell
python manage.py runserver
admin page URL http://127.0.0.1:8000/admin/ When you log in, you will see something like the following
polls/admin.py
from django.contrib import admin
from .models import Question
admin.site.register(Question)
The polls app column has been added as below
Click Questions to work with the values in the object
I want to use it well because it is easier to understand than operating from the shell.
Creating your first Django app, part 3 https://docs.djangoproject.com/ja/3.1/intro/tutorial03/
polls/views.py
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world. You're at the polls index.")
def detail(request, question_id):
return HttpResponse("You're looking at question %s." % question_id)
def results(request, question_id):
response = "You're looking at the results of question %s."
return HttpResponse(response % question_id)
def vote(request, question_id):
return HttpResponse("You're voting on question %s." % question_id)
polls/urls.py
from django.urls import path
from . import views
urlpatterns = [
# ex: /polls/
path('', views.index, name='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'),
]
Now when you open python manage.py runserver and the following URL in your browser, detail (), results () and vote () in polls / views.py will be executed respectively. http://127.0.0.1:8000/polls/34/ http://127.0.0.1:8000/polls/34/results/ http://127.0.0.1:8000/polls/34/vote/
Rewrite index () in polls / views.py as follows: Question.
polls/vies.py
from django.http import HttpResponse
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
output = ', '.join([q.question_text for q in latest_question_list])
return HttpResponse(output)
def detail(request, question_id):
return HttpResponse("You're looking at question %s." % question_id)
def results(request, question_id):
response = "You're looking at the results of question %s."
return HttpResponse(response % question_id)
def vote(request, question_id):
return HttpResponse("You're voting on question %s." % question_id)
In the above, the screen layout is written directly in views.py, but let's separate the description in template so that it can be easily modified. Write loader.get_template ('polls / index.html') in views.py to read template / polls / index.html.
polls/views.py
from django.http import HttpResponse
from django.template import loader
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
template = loader.get_template('polls/index.html')
context = {
'latest_question_list': latest_question_list,
}
return HttpResponse(template.render(context, request))
polls/templates/polls/index.html
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
render
If you replace the template reading and rendering with render (), you can write it short, and you can import fewer packages.
polls/views.py
from django.shortcuts import render
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
return render(request, 'polls/index.html', context)
Causes a 404 to be issued when an exception occurs with try / except.
polls/views.py
from django.http import Http404
from django.shortcuts import render
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
return render(request, 'polls/index.html', context)
def detail(request, question_id):
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404("Question does not exist")
return render(request, 'polls/detail.html', {'question': question})
get_object_or_404
It is troublesome to try / exclude each time, so I will replace it with get_object_or_404 () which is a function that returns 404 if it fails.
python
from django.shortcuts import get_object_or_404, render
from .models import Question
# ...
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question})
If you specify app_name in polls / urls.py, you can refer to it from the namespace of the app. If you do not do this, the operation will be suspicious when there is a view with the same name in another application, so I think it is better to specify it when creating a view without forgetting.
polls/urls.py
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.index, name='index'),
path('<int:question_id>/', views.detail, name='detail'),
path('<int:question_id>/results/', views.results, name='results'),
path('<int:question_id>/vote/', views.vote, name='vote'),
]
This will change the view reference from detail to polls: detail. Respecify other views as polls: hoge as well.
polls/templates/polls/index.html
{% 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 %}
Creating your first Django app, part 4 https://docs.djangoproject.com/ja/3.1/intro/tutorial04/
Add a vote button
polls/detail.html
<h1>{{ question.question_text }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% 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 %}
<input type="submit" value="Vote">
</form>
You can make a button like this http://127.0.0.1:8000/polls/1/ Since the action of the form is set to "post to the view of polls: vote", create a view corresponding to this.
The view of polls: vote is written in polls / urls.py as follows, so you can write it in polls / views.py.
polls/urls.py
path('<int:question_id>/vote/', views.vote, name='vote'),
Add one of the selected targets and redirect to / polls / results /
polls/views.py
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from .models import Choice, Question
def 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,)))
I will also write a view of / polls / results / called by redirect
python
from django.shortcuts import get_object_or_404, render
def results(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/results.html', {'question': question})
It seems that useless descriptions can be reduced by using a general-purpose view.
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'),
]
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 .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."""
return Question.objects.order_by('-pub_date')[:5]
class DetailView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
class ResultsView(generic.DetailView):
model = Question
template_name = 'polls/results.html'
It's still going on https://docs.djangoproject.com/ja/3.1/intro/tutorial05/
Recommended Posts