見出し画像

【Django公式サイト チュートリアル(3)】urlsとviewsの連携。

こんにちは(@t_kun_kamakiri

引き続きDjangoの公式サイトにあるチュートリアルを見ながら学習を進めたいと思います。


基本的には公式ドキュメントを見れば良いのですが、ここでは勉強ログとしてわからない点などまとめながら進めていきます。

【本日の内容】
●「urls.py」でURLのリクエストを設定
●リクエストに応じた関数を「views.py」に書く

djangoの仕様として以下の流れでWeb上に表示をさせています。

画像1

まず、プロジェクトの「urls.py」からどのアプリを起動させるかを指定します。今回は「polls」というアプリです。
その後に、「polls/urls.py」の中で指定したURLのリクエストを指定します。
URLが指定されたら、どういった操作をするのかを「views.py」に書きます。

「urls.py」でURLのリクエストを設定

まず、「polls/urls.py」は以下のようにしておきます。

from django.contrib import admin
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'),
]

例えば、

path('<int:question_id>/', views.detail, name='detail'),

のようにしている部分は、「'<int:question_id>/'」にアクセスがあったら、「 views.detail」(views.pyのdetail関数)という操作を行ってくださいという指示になります。

なので、「views.py」を以下のようにします。

from django.shortcuts import render
from django.template import loader
from .models import Question

# Create your views here.
def hellofunc(request):
   return HttpResponse("やっほー")

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):
   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)

これらの関係性をざっくり矢印で結びました。

画像2

ここまでできたら、開発用サーバーを立ち上げて、

python3 manage.py runserver

http://127.0.0.1:8000/polls/34/

にアクセスしてみましょう。
アクセスすると以下のようになっているのが確認できたらOKです。

画像3

htmlファイルを作成してWeb上に表示

「urls.py」の中に、

path('', views.index, name='index'),

があるのですが、これは
/polls/“がリクエストされるとviews.index関数が操作する
という意味です。

画像4

● latest_question_list = Question.objects.order_by('-pub_date')[:5]
で、なにやらデータを格納しているのがわかります。
まだ何かはわからないので、後ほどhtmlで表示させるようにしておきます。

● context = {'latest_question_list': latest_question_list}
がPythonの辞書型になっていて、'latest_question_list'というキーに対して「latest_question_list = Question.objects.order_by('-pub_date')[:5]」で設定したデータが関連付けられています。

●return render(request, 'polls/index.html', context)
で「index.html」を呼び出して、上で記述した「context」を引数として渡しています。

しかし、「index.html」はどこにも設定していないので、今から設定します。

htmlファイルは「templates」というディレクトリを作成して、その中に入れていく必要があります。

【テンプレートの名前空間】
作ったテンプレートを (polls という別のサブディレクトリを作らずに) 直接 polls/templates の中に置いてもいいのではないか、と思うかもしれませんね。しかし、それは実際には悪い考えです。Django は、名前がマッチした最初のテンプレートを使用するので、もし 異なる アプリケーションの中に同じ名前のテンプレートがあった場合、Django はそれらを区別することができません。そのため、Django に正しいテンプレートを教えてあげる必要がありますが、一番簡単な方法は、それらに 名前空間を与える ことです。アプリケーションと同じ名前をつけた もう一つの ディレクトリの中にテンプレートを置いたのは、そういうわけなのです。

画像5

「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 %}

htmlファイルの中でPythonのコードを書く際には「{% %}」で囲むという決まりがdjangoの決まりとなっています。

views.pyで設定した以下の2つがindex.htmlに引き渡されていることを確認しておきます。

● latest_question_list = Question.objects.order_by('-pub_date')[:5]
● context = {'latest_question_list': latest_question_list}

これだけでは、「index.html」をWeb上で表示することはできません。
「index.html」をどこに保存しているのか指定する必要があります。

それが「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',
           ],
       },
   },
]
'DIRS': [BASE_DIR,'templates'],
↑ここですね。

ファイル内の上の方で、
BASE_DIR = Path(__file__).resolve(strict=True).parent.parent
と定義しているので、現在のプロジェクトのディレクトリだということ・・・かと思います。
その中の「templates」ディレクトリの中にhtmlファイルを指定するという意味になります。

さらに、

「urls.py」を以下のように「app_name = 'polls'」を追加します。

from django.contrib import admin
from django.urls import path
from . import views

app_name = 'polls'
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'),
]

その理由を知るために、「index.html」を以下のように変更します。

{% if latest_question_list %}
   <ul>
   {% for question in latest_question_list %}
       <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
       <li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
   {% endfor %}
   </ul>
{% else %}
   <p>No polls are available.</p>
{% endif %}
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>


はどちらも「'polls/数字'」とリクエストがあったときに、「urls.py」で指定したdetail関数が呼び出されますが・・・・
2行目の「"{% url 'polls:detail' question.id %}"」には、pollsのurls.pyで書いた「path('<int:question_id>/', views.detail, name='detail'),」
※name='detail'です。
にと関連付けできていません。

なので、「polls/urls.py」の中に「app_name = 'polls'」として設定する必要があります。

チュートリアルには以下のように書かれています。

【URL 名の名前空間¶】
このチュートリアルプロジェクトが持つアプリは polls アプリ1つだけです。実際の Django プロジェクトでは、5個、10個、20個、あるいはそれ以上のアプリがあるかもしれません。 Django はどうやってこれらの間の URL 名を区別するのでしょうか? 例えば、 polls アプリは detail ビューを含みますが、同じプロジェクトにブログのためのアプリがあり、そのアプリも同名のビューを含むかもしれません。 {% url %} テンプレートタグを使ったとき、 Django はどのアプリのビューに対して url を作成すればいいでしょうか? これを Django にどう知らせればいいでしょうか。
答えは、 URLconf に名前空間を追加すること、です。どうぞ polls/urls.py ファイル内で app_name を追加し、アプリケーションの名前空間を設定してください。

要するに「polls:detail」がどこにあるのかを知らせるために、名前空間を設定しているという事ですね。

名前空間とは、例えば通常同じファイルに同じクラスや関数名、定数名が存在することはできませんが、名前空間を使用することにより、関連するクラスや、インターフェイス、関数、定数などをグループ化することが可能です。

では、これで「index.html」がWeb上に表示されるかを確認してみましょう。

python3 manage.py runserver

http://127.0.0.1:8000/polls/

として表示してみましょう。

画像6

画像8

以上の流れを書いておきます。

画像7

チュートリアルを読みながら理解が深まってきました('ω')
無料で勉強できていいですね。

本日は以上です。

持ってるDjangoの書籍

僕は以下の2冊の書籍を持っています。
書籍はまとまって勉強できるので、気に入ったやつを手元に置いておくといいですよね。

この2冊は入門としては良いのではないですかね。
とくに、「Pyton Django3超入門」はかなりわかりやすく書かれているので読んでいて楽しいです。

Twitter➡@t_kun_kamakiri
ブログ➡宇宙に入ったカマキリ(物理ブログ)
ココナラ➡物理の質問サポートサービス


この記事が気に入ったらサポートをしてみませんか?