Django

DjangoでビューとテンプレートとURLディスパッチャを使ってとりあえずのページを表示する【Django学習記録】

DjangoでビューとテンプレートとURLディスパッチャを使ってとりあえずのページを表示するの概要

注意 ※バージョンや環境によっては正常に動作しない可能性があります。

Djangoに限らずですが、初心者の方がプログラミングを勉強すると、実際にこれを使ってどうやって役に立つものを作るの? と良くわからなくなることがあります。

これは知識がないことも理由の1つですし、本などで前提部分を読まずにとりあえずhello worldを表示するを試したり、なんてことをしがちだからかな~とか、思ったりします。

例えばDjangoはPythonで作ったWeb用のフレームワーク、なのですが、初心者だとこの言葉だけではさっぱりわからないわけですね。

Djangoの場合、一番手っ取り早いのは、データベースの値を参照して、その値をテンプレートに渡してHTMLのページを表示するプログラムを作ることなんでしょうけど、初心者にはハードル高いよな~と思ったりします。

まず、環境を作ることで精いっぱいだったりしますよね~。

今回は、Djangoの重要な要素である「モデル」はいったん置いておいて、「ビュー(views.py)」と「テンプレート」と「URLディスパッチャ(urls.py)」を使って、とりあえず適当にページを表示させたいと思います。

「TOPページに単純なWebページを表示させる」が今回の目的です。

test-siteプロジェクト内に、topというアプリケーションを作り、トップページを表示させます。

処理としては、アクセス(リクエスト)があると、アクセスがあったURLに指定された処理をして、表示用のデータを返すと、リクエストがあったPCのブラウザがそのデータを受け取って、画面に表示する、というのが一連の流れです。

「アクセスがあったURLに指定された処理」を決めているのがurls.pyで、「処理をして表示用のデータを返す」のがviews.pyで、表示用のHTMLのひな形が「テンプレート」になります。

環境はPython3.8のDjango3.1です。

アプリケーションの登録

アプリ登録メモ

  • setting.pyにアプリを登録
  • INSTALLED_APPS内に「パッケージ」.「モジュール」.「クラス」とアプリを指定する
  • 今回のケースは「top.apps.TopConfig」

以下の記事で示したアプリが作られているのが前提です。

Djangoのプロジェクトとアプリケーションを仮想環境で作る【Django】
Djangoのプロジェクトを仮想環境で作るの概要 注意 ※バージョンや環境によっては正常に動作しない可能性があります。 Pipenvで作ったPythonの仮想環境にDjangoをインストールし、最低限のプロジェクトを作る記事です。 ...

この記事で作成したアプリをsetting.pyに登録しておきます。

これをやっとかないと動きません。

# Application definition

INSTALLED_APPS = [
    'top.apps.TopConfig', #追加
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

INSTALLED_APPS =[]内ならば、どこに追加しても大丈夫です。

DjangoがこのINSTALLED_APPSを呼び出す処理の時に、上に記述したアプリから処理されます。

カンマを忘れやすいので注意が必要です。

これで動くようになります。

その他のINSTALLED_APPS記載の、django.contrib.admin以下のアプリは、Djangoのプロジェクトを作った時にデフォルトで作られるものです。

フレームワークが準備してくれている機能ですね。

adminは良く出てきます。データベースを扱う管理画面とか、プロジェクトのユーザーの設定などができます。管理にだけ使うことも可能ですし、ブログのログイン機能のように使うこともできます。

TopConfigはどこからきたのか

アプリケーションtopを作ると、以下のようにtopフォルダ内にファイルが作られます。

test-site
│
├── manage.py
├── db.sqlite3
│
├── config
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   ├── wsgi.py
│   └── __init__.py
│
└── top
    ├── admin.py
    ├── apps.py
    ├── models.py
    ├── tests.py
    ├── views.py
    ├── __init__.py
    │
    └─migrations
      └── __init__.py

このapps.pyの中に以下の記述があります。

from django.apps import AppConfig

class TopConfig(AppConfig):
    name = 'top'

アプリを作ると、自動でこのファイルが作られるのですが、この時のクラス名TopConfigをsetting.pyのINSTALLED_APPSに設定しています。

topアプリの、apps.pyのクラス名TopConfigってことですかね。

URLディスパッチャ

非常に大まかに雑に言ってしまえば、DjangoはWebサイトを作るためのフレームワークです。

なので、「Webページが表示される処理」が前提になります。

Webページが表示される時に何が起きているのかをここでは詳しく説明しませんが、リクエストがきて、それにレスポンスを返す、というのが基本です。

「WebサイトURLにアクセスすると指定のページが表示される」というのがわかりやすいですかね。

URLディスパッチャとは、URLにアクセスしたときの処理を決めておく、という機能です。

難しく言うと定義する、なんて言葉になります。

あくまでURLディスパッチャでは、「アクセスがあった時にこの処理をするね」、というのを決めているだけです。

では実際の処理はどこに書いてあるの、というとビューに書きます。

URLディスパッチャでは、とあるURLにアクセスがあったら、views.pyに書いてある特定のクラス・関数を呼び出すよ、というふうに書いてあります。

URLディスパッチャの詳細についてはDjango公式の以下のページを参照してください。

Django
The web framework for perfectionists with deadlines.

実際の設定

URLディスパッチャのメモ

  • config内にあるurls.pyにtopのurls.pyを使うよ宣言
  • topアプリにurls.pyを作成
  • top内のurls.pyに、トップのURLにアクセスがあった時に呼び出すviews.pyの関数を指定する

config内のurls.py

まず、config内にあるurls.pyに、他のアプリのurls.pyを使うよ、という記述をします。

トップページにアクセスがあったら、topアプリのurls.pyを使ってね、という指示です。

以下、config内のurls.pyです。

from django.contrib import admin
from django.urls import path, include    #includeを追加

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('top.urls'))    #追加
]

デフォルトで、admin管理画面のURLが設定されています。

セキュリティを気にするならば、Web上で使う時は、ワードプレスの管理者ログイン画面と同じように、URLを変更しておいた方が良いのかな、と思います。

まず、include関数をインポートしておきます。

includeの詳細は以下でどうぞ。

Django
The web framework for perfectionists with deadlines.

urlpatternsは公式のリファレンスにありますが、リクエスト処理があった時に呼び出されるもので、urlpatterns内の設定を上から順に呼び出していき、条件に合うものを返します。

今回はtopというアプリで、サイトのトップページを表示する、です。ドメイン「なんとか.com/」にアクセスがあった時、といった感じです。

なので、path('', include('top.urls'))としてトップページにアクセスがあったら、topアプリのurls.pyを参照してね、ときめています。

例えばtestアプリを仮に作ったとして、「なんとか.com/test/」とその配下にアクセスがきたら、testアプリのビューで処理をする、としたいのならば、 path('test/', include('test.urls'))と書きます。

pathの中で、URLのドメイン/以下を指定し、その指定に対して呼び出すURLを指定します。includeを使うことで、他のアプリにあるurls.pyを使うよと指定できます。

topアプリ内にurls.pyを作る

次に、topアプリ内にurls.pyを作ります。

Django3.1の段階では、アプリ作成時に自動で作られるファイルの中にurls.pyはありません。

なので自分で新規ファイルを作成します。

topアプリ内のurls.pyには以下を記述します。

トップページにアクセスがあったら、views.pyにあるtop_page関数を使ってね、という記述です。

from django.urls import path
from . import views

app_name = 'top'

urlpatterns = [
    path('', views.top_page, name='top_page')
]

configのurls.pyで、「なんとか.com/」にアクセスがあったらtopアプリのurls.pyを使うと定義してあります。

urlpatternsはconfigの時と同じです。

urlpatternsの中にpath()で処理を記述します。

pathには、''を指定して、そこにアクセスがあったら、views.pyのtop_page関数の処理を実行する、と定義しています。

例えば、topアプリ内で「なんとか.com/blog/」に来た時の処理も書きたいのならば、path('blog/', views.blog_page, name='blog_page') なんて書きます。

app_nameと、path内のnameはURLの逆引きの時に使います。今回は触れません。

path()とre_path()とurl()

ビューについて触れる前に、ちょっと寄り道します。

古いDjangoの記事を読んでいると、url()とか出てくるんですよね。

これなんだろ、と思ってちょっと調べたんですけど、どうもDjangoの1.系ではurl()で指定してたんですね。

3.1の公式でURLディスパッチャのところを読んでいてもurl()とかないので、現状では使わない感じですかね。公式の中にurlpatternsの変数の値はdjango.urls.path() または django.urls.re_path() インスタンスの sequence でないとダメ、とも書いてあります。

path()とre_pathの違いは、ざっくり簡単に言ってしまうと、正規表現の呼び出しにはre_pathを使う、通常の呼び出しはpathを使う、ぐらいの認識なのかな、と思います。厳密にはもっと色々あるんでしょうけど。

ビュー

ビューのメモ

  • views.pyに関数「top_page」を作る
  • top_page内で、テンプレートに渡す辞書型contextを定義する
  • 戻り値returnにrender関数を指定する
  • render関数で呼び出すテンプレートとテンプレートに渡す変数を指定する

urls.pyで、トップページにアクセスがあったら、views.pyのtop_page関数で処理をしてね、としました。

なので、top_page関数を作ります。

from django.shortcuts import render

def top_page(request):
    context = {
        'type' : 'トップページ',
    }
    return render(request, 'top/top_page.html', context)

top_page関数を呼び出したら、top_page.htmlファイルにcontextのデータを渡して表示データを作ってそれを戻してね、という処理です。

Webページを表示したいので、リクエストに対してレスポンスを返す必要があります。レスポンスはtop_page関数の戻り値(return)にrender関数を指定して設定します。

Webページは大体htmlで作成されます。なので、どのhtmlファイルを使うのかを指定する必要があります。これがテンプレートの指定です。

追加で、テンプレートに変数を渡すことができるため、その設定もしています。

コードの説明

最初の一行で、renderを使うために、「from django.shortcuts import render」でrenderをインポートします。

次に、関数を指定します。def 関数名(引数)で作ります。引数はrequestとしています。関数の作り方はPythonの知識が必要です。

requestはDjangoが作るオブジェクトです。URLにアクセスする場合、クライアント側(すごく単純化していってしまうと個人とかで使っているPC)のリクエスト情報をまとめています。

何を呼び足せるのかは以下の公式を確認してください。とりあえず動かすだけならば読む必要はないですが。

Django
The web framework for perfectionists with deadlines.

context= の場所では、テンプレートに渡す辞書型の変数を定義しています。contextとしていますが、名前は任意です。

renderは第1引数でrequestオブジェクト、第2引数で呼び出すテンプレートを、第3引数はなくても良い任意で、辞書を受け取ります。

このrender関数はショートカット関数と呼ばれていまして、HTTPリクエスト・レスポンス周りの処理を、まとめて内部的に行ってくれるているものになります。

django3.1でアプリを作ると、views.pyにはデフォルトでimportでrenderの記述があるんですよね。レスポンスでテンプレートを使うは場合はこれを使ってね、という感じなんですかね。

じゃあ実際にrender関数って何をしているのかというと、HttpResponseやloaderを合わせた動きをしてくれます。

テンプレートを呼び、使いたい値をcontext引数に入れ、テンプレートをレンダリングして、そのページをHttpResponseで返す、というのは一つ一つ個別に関数で処理できるのですが、良く出てくる動作なので、render関数でまとめてくれている、という感じですかね。

とりあえずこれで、トップページにアクセスがあった時の処理ができました。

次は、render関数で指定したテンプレートを作ります。

テンプレート

HTMLのテンプレートファイルですが、保存としておくフォルダがDjangoの仕様上ちょっとめんどくさい形になっています。

topアプリ内で使用するテンプレートファイルは、topフォルダ内にまず「templates」というフォルダを作り、その中にさらにアプリ名の「top」でフォルダを作り、その中に保存します。

二つ目のtopフォルダ内にさらにフォルダを作ることも可能です。

テンプレート用のファイルを作ると、以下のようなフォルダ構成になりすま。

test-site
│
├── manage.py
├── db.sqlite3
│
├── config
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   ├── wsgi.py
│   └── __init__.py
│
└── top
    ├── admin.py
    ├── apps.py
    ├── models.py
    ├── tests.py
    ├── urls.py
    ├── views.py
    ├── __init__.py
    │
    ├─ migrations
    │   └── __init__.py
    │
    └─ templates
        └── top
            ├── base.html
            └── top_page.html

ベースになるHTMLファイルを作る

Webページを作るとき、HTMLのソースコードには共通部分がたくさんあります。

各種テンプレートファイルに同じ記述をしなくてもいいように、ベースになるファイルを作っておくことができます。

以下が、ベースになるbase.htmlです。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>{% block tiltle %}{% endblock %}</title>
  <meta name="description" content="{% block description %}{% endblock %}">
</head>

<body>
  <header>
    ヘッダー
  </header>

  <main>
    {% block contents %}{% endblock %}
  </main>

  <footer>
    フッター
  </footer>


</body>
</html>

{% block 名前 %}{% endblock %}という形で書いてあるところが、各ページのテンプレートファイルで設定する場所です。名前は任意です。

metaでの文字コードやヘッダーやフッターは全ページ共通で、titleタグやメインコンテンツだけ変える、みたいな感じで作ることができます。

その他、headタグ要素なども共通化しやすいですね。

このbase.htmlを使って呼びだしたページは、{% block 名前 %}{% endblock %}で定義した場所以外は全部共通になるのです。

一部を変えたいならば、ベースとなるファイルを複数作ることになります。

topページのテンプレートを作る

次に、topページのテンプレを作ります。

{% block 名前 %}{% endblock %}中に入るものを作る、と考えて良いです。

{% extends 'top/base.html' %}

{% block tiltle %}トップページ|Django学習用テストサイト {% endblock %}

{% block description %}Django学習用のテストで作った際とのトップページ。{% endblock %}

{% block contents %}

<h1>{{ type }}</h1>

<p>pタグ</p>

<ul>
  <li>liタグ1</li>
  <li>liタグ2</li>
  <li>liタグ3</li>
</ul>

{% endblock %}

まず、{% extends ‘top/base.html’ %}として、base.htmlを使うことを宣言します。

このextendsで呼ぶファイルを変えれば、ベースになるHTMLを変えることができます。

{% block contents %}で囲んだ部分が、base.htmlの{% block contents %}の場所に表示されます。titleタグ、descriptionも同様です。

{{ type }}とあるのは、views.pyで作った辞書型のデータcontextのtypeを呼んでいます。辞書型のkeyを指定することで、value要素を呼び出せます。

こんな感じで変数をテンプレートに渡すことができます。

開発サーバーでローカルホストに接続する

さて、これでページの準備ができました。

開発環境での表示になるため、ローカルホストhttp://localhost:8000/で接続します。

Djangoのポート番号については以下に記載があります。

Django
The web framework for perfectionists with deadlines.

ローカルホストにアクセスする前に、Djangoの開発サーバーを起動します。

(.venv) C:\python_venv\test-site>python manage.py runserver

マイグレーションをしていないので正しく動作しないかも~みたいな警告文が出ますが、今回はとりあえず無視して良いです。

何にもないですが、こんな感じでページが表示されます。

contextで設定したtypeのvalue「トップページ」もきちんと表示されています。

これで、Djangoで「TOPページに単純なWebページを表示させる」が実現できましたた。

開発サーバーを終了するには、Windowsのコマンドプロンプトだと、CTRL + c です。

まとめ

この記事でメモったこと

  • setting.pyにtopアプリのapps.pyのクラスTopConfigを登録
  • configのurls.pyに、トップページにアクセスがあったら、topアプリのurls.pyを使うように設定
  • topアプリのurls.pyに、トップページにアクセスがあったら、views.pyのtop_page関数を呼び出すように設定
  • top_page関数の処理を作成(リクエストを受けたら、top_page.htmlとcontextを上手いことやって表示データを戻すようにしてね)
  • テンプレートのベースになるbase.htmlを作成
  • トップページの中身top_page.htmlを作成

ざっと駆け足で見てきましたが、DjangoでWebページを表示する一連の流れは示せたかな~と思います。

各項目は細かく掘り下げれば掘り下げられるのですが、今回はざっくりページを表示することだけを目的にしました。

そうは言ってもただ「hello world」を表示するだけでは面白くないし、でも仕組みの骨格はメモしておきたいし…と考えた結果、こんな感じになりました。

基本は自分の学習用のメモでして、自分が理解しようと思ったときにたどった思考の流れをそのまま書いています。そのため、冗長な文章になっています。

ただ、自分はこういう冗長な書き方をしておかないと理解が進まないタイプなので、ああだこうだ色々書いておくスタイルになります。

あと、厳密に言うとちょっと違うんだけど理解するために端折っちゃうね、とか、言いかえちゃうね、みたいな部分も多いので、ちゃんとした人には怒られるかもな~とも思います。

わかりやすい説明を求める人や厳密さを求める人には向かないので申し訳ないのですが、自分と同じようなタイプの人に役に立つといいな~と思います。

タイトルとURLをコピーしました