📚

Python+Djangoを使ってWebページベースの画面を出力する方法

に公開

概要

IT技術系のオンラインサロンでペアプロ開発をしているんですが、そのリマインドも兼ねてシェアしようと思います。

著者のステータス

フロントエンドエンジニアをしています。
実務では主にJS系のプロジェクトが多いため、Pythonは完全初心者レベルです。
今回の感触としてはDjango独自の規則などもありやや難儀した部分もありますが、routesやループなどの構造・記述方法が実装を通じてわかるようになってきました。

開発環境

  • Python 3.7.4
  • OS:MacOS ver 11.1 (Big Sur)
  • エディタ:VS Code

参考文献

Django公式ドキュメント
はじめての Django アプリ作成、その 1
Djangoのテンプレート機能を使ってみる

開発手順

djangoプロジェクト、アプリの作成

Pythonをインストールした状態でターミナルから開発ディレクトリに移動し、コマンドを入力します。
今回は「todo_site」というプロジェクト名を使うため、下記のようになります。

django-admin startproject todo_site

さらに下記コマンドで、プロジェクトの中に「todo_app」アプリを作成します。

python manage.py startapp todo_app

このアプリをプロジェクトで読み込みさせるため、「todo_site」内の設定ファイルでアプリ一覧に該当アプリ名を追加します。

todo_site/settings.py(抜粋)
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'todo_app',     #追加した行
]

これで下準備は整いました。

Webview構造の実装

今回作っているのはこの2ページです。

  • インデックスページ(index):テキスト表示のみ
  • ユーザーリストページ(user_list):外部css読み込み、ループ処理を使ったリスト表示

まず各ページのパス構成を定義するため、パス名やテンプレートを下記のように記述します。

todo_site/todo_app/urls.py
from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
    path('user_list/', views.user_list, name='user_list'),
]

viewsviews.pyで定義された関数の呼び出しになるので、次に下記のように定義します。

todo_site/todo_app/views.py
from django.shortcuts import render
from django.http import HttpResponse

def index(request):
    return HttpResponse("hogehogehoge")

def user_list(request):
    # ユーザーリスト
    context = {
        "items" : [
            {
                "user_name" : "ユーザー1",
                "talk" : "トーク内容",
                "updatetime" : "12:00",
            },
            {
                "user_name" : "ユーザー2",
                "talk" : "トーク内容",
                "updatetime" : "12:00",
            },
            {
                "user_name" : "ユーザー3",
                "talk" : "トーク内容",
                "updatetime" : "12:00",
            },
        ]
    }
    
    return render(request, 'todo_app/user_list.html', context)

indexページは単純にテキストのみを表示させるため、HttpResponseをインポートしています。
一方でユーザーリストページはカード形式のリストをループで表示させる仕様の実装なので、このファイルではリストの内容を変数contextで定義し、別のテンプレートファイルを用いてview側に落とし込むという構成をとっています。

テンプレートを使ったviewの実装

views.py内のレンダリング文で記載したtodo_app/user_list.htmlの該当テンプレートファイルを作成します。

djangoのファイル参照の仕様上、複数のindex.htmlファイルを作成した時を考慮してディレクトリを二重にする事が推奨されている。

という部分で個人的に違和感が残ったのですが、ルールに伴い下記のように実装しました。

todo_site/todo_app/templates/todo_app/user_list.html
{% load static %}

<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Hello, world!</title>
<link rel="stylesheet" href="{% static 'todo_app/css/user_list.css' %}">
</head>
<body>
    {% for item in items %}
        <div class="item">
            <div class="item-icon">icon</div>
            <div class="item-detail">
                <div class="item-detail-username">{{ item.user_name }}</div>
                <div class="item-detail-talk">{{ item.talk }}</div>
            </div>
            <div class="item-status">
                <div class="item-status-updatetime">{{ item.updatetime }}</div>
            </div>
        </div>
    {% endfor %}
</body>
</html>

views.py内、context関数の中で定義したitemsを読み込み、pythonのループ処理で出力しているという構造です。

さらに

load static
<link rel="stylesheet" href="{% static 'todo_app/css/user_list.css' %}">

の2文で下記外部CSSを読み込んでいます。
外部ソース用のディレクトリ「static」を新規作成しています。

todo_site/todo_app/static/todo_app/css/user_list.css(抜粋)
.item {
    height: 60px;
    width: 250px;
    border: solid 1px #000;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0px 5px;
}

そして下記コマンドかVSCodeのメニューから実行することでアプリを立ち上げます。

python manage.py runserver

最終的なビューはこの様になりました。

  • インデックスページ

スクリーンショット 2021-03-12 18.47.14.png

  • ユーザーリストページ

スクリーンショット 2021-03-12 18.47.27.png

Discussion