(Python)Djangoを使ってWebアプリケーション開発に挑戦してみる

# はじめに
API の実行結果を HTML でみてみたい。
という事で、まずは localhost で API をを実行してブラウザに結果を HTML 表示できないか調べてみた。
結果、`Django`を勉強しなさいと言われたので、　とりあえず挑戦してみる。

# Django
Django について軽く説明する。

- Python で作られたフルスタック・フレームワークである。
  - 必要なものはすべて揃っている。
  - テンプレートはあれを持ってきて、DB アクセスはあれを持ってきて、ということがない。
  - 拡張するモジュールはあるが、基本は Django だけで完結する。

- ORM - Object Relational Mapping オブジェクト関係マッピング が優れている。
- 学習コストが低い
 - 生の HTML、Javascript、CSS が基本だったりするが、最初に選ぶWebフレームワークとしてはシンプル。

# 開発の流れ
初めての`Django`を使った開発なので、サンプルアプリケーションとして書籍一覧を作成してみる。
以下の流れに沿って開発を進める。

1. `Django`をインストール、プロジェクトを作成する。
2. データベースのセットアップをする。
3. 開発用サーバの起動する。
4. アプリケーションを作成する。
5. Bootstrapを導入する。
6. viewsとURLスキームを作成する。
7. HTMLを作成する。

# 環境
実行環境は以下

```
$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.15.1
BuildVersion:   19B88

$ python --version
Python 3.7.4
```
仮装開発環境として`venv`を使用する。

# 1. Djangoをインストール、プロジェクトを作成する
今回は安定バージョンを使用したいので、バージョンを指定してインストールする。

```
$ pip install django==2.1.5
```

続いてプロジェクトを作成する。
今回は mybook というプロジェクトを作成する。

```
$ django-admin.py startproject mybook
```
以下の構成でプロジェクトが作成される。

```
mybook/
    manage.py
    mybook/
        __init__.py
        settings.py
        urls.py
        wsgi.py
```
ここで`mybook`ディレクトリに移動しておく。

```
$ cd mybook
```

# 2. データベースをセットアップする
データベースの設定は、`mybook/settings.py`で行う事ができる。
今回は初期設定`SQlite3`のを使用する。

```settings.py
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

    :

# Database
# https://docs.djangoproject.com/en/1.9/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}
```

データベースをマイグレートするコマンドを入れると、プロジェクト直下のディレクトリに`db.sqlite3`というファイルが作成される。

```
$ python manage.py migrate
```
併せて、スーパーユーザーを作成する。

```
$ python manage.py createsuperuser
Username (leave blank to use 'hoge'): admin
Email address: admin@example.com
Password: hogefuga
Password (again): hogefuga
Superuser created successfully.
```
途中、以下の質問に答える。

- ユーザー名: admin
- メールアドレス: admin@example.com ※適当
- パスワード: hogefuga
- パスワード(再入力): hogefuga

# 3. 開発用サーバの起動する
`python manage.py runserver`というコマンドで開発用サーバを起動し、プロジェクトが動くか確認する。

```
$ python manage.py runserver
```
ブラウザで http://127.0.0.1:8000/ にアクセスする。
<img width="1172" alt="スクリーンショット 2019-12-29 20.04.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472784/a444b84f-c51a-277f-ff98-500180c4549d.png">
開発用サーバの終了は、`control + c`で行う。

# 4. アプリケーションを作成する
プロジェクトの下に`cms`というアプリケーションを作成する。
以下のコマンドで作成する。

```
$ python manage.py startapp cms
```
mybook プロジェクトのディレクトリの下に、以下のファイルが作成される。

```
mybook/
    cms/
        __init__.py
        admin.py
        apps.py
        migrations/
            __init__.py
        models.py
        tests.py
        views.py
    manage.py
    mybook/
       :
       :
```
データベースに定義したいデータ モデルを、`cms/models.py`に定義する。

```models.py
from django.db import models


class Book(models.Model):
    """書籍"""
    name = models.CharField('書籍名', max_length=255)
    publisher = models.CharField('出版社', max_length=255, blank=True)
    page = models.IntegerField('ページ数', blank=True, default=0)

    def __str__(self):
        return self.name
```
`mybook/settings.py`の INSTALLED_APPS の最後に`cms`を追加する。

```settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'cms',  # 追加

]
```
以下のコマンドで、`models.py`の変更を拾って、マイグレートファイルを作成する。

```
$ python manage.py sqlmigrate cms 0001
```
まだデータベースに反映していないマイグレートファイルを、以下のコマンドでデータベースに反映する。

```
python manage.py migrate cms
```
ここまでで、データベースの準備が完了した。

# ５. Bootstrap を導入する
ここからフォロンとの作成を行っていく。
今回は、CSS フレームワークの Bootstrap を使う。
Bootstrap で必要な jQuery を含めて、以下からダウンロードします。

- Bootstrap - http://getbootstrap.com/ 
- jQuery - http://jquery.com/ 

ダウンロードしたファイルを、`mybook/cms/static/cms/`というディレクトリを作って、以下のように配置する。

```
mybook
└── cms
    └── static
        └── cms
            ├── css
            │   ├── bootstrap.min.css
            │   └── bootstrap.min.css.map
            └── js
                ├── bootstrap.bundle.min.js
                ├── bootstrap.bundle.min.js.map
                └── jquery-3.4.1.min.js
```

# 6. viewsとURLスキームを作成する
一覧のファンクションが必要なので、`cms/views.py`に作成する。

```views.py
from django.shortcuts import render
from django.http import HttpResponse


def book_list(request):
    """書籍の一覧"""
    books = Book.objects.all().order_by('id')
    return render(request,
                  'cms/book_list.html',     # 使用するテンプレート
                  {'books': books})         # テンプレートに渡すデータ
```
続いて URL スキームを作成する。
`cms/urls.py`というファイルは存在しないので、新しく作成する。
この中で、URL と、ビューのファンクションの紐付けを行う。

```cms/urls.py
from django.urls import path
from cms import views

app_name = 'cms'
urlpatterns = [
    # 書籍
    path('book/', views.book_list, name='book_list'),   # 一覧
]
```
次に、`cms/urls.py`をプロジェクト全体の`mybook/urls.py`の中でインクルードする。

```mybook/urls.py
from django.contrib import admin
from django.urls import path, include   # ←, includeを追加

urlpatterns = [
    path('cms/', include('cms.urls')),   # ←ここを追加
    path('admin/', admin.site.urls),
]
```
最終的に URL は以下のようになる。

```
http://127.0.0.1:8000/cms/book/
```

# 7. HTMLを作成する
mybook プロジェクトの cms アプリケーションで使う`book_list.html`というテンプレートを作成する。
はじめに、継承元となる`base.html`というテンプレートを作成する。

```
mybook/cms/templates/cms/base.html
```
`base.html`の中身は、以下のとおり。

```base.html
{% load i18n static %}
<!DOCTYPE html>{% get_current_language as LANGUAGE_CODE %}
<html lang="{{ LANGUAGE_CODE|default:"en-us" }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="{% static 'cms/css/bootstrap.min.css' %}">
{% block extra_css %}{% endblock %}
<title>{% block title %}My books{% endblock %}</title>
</head>
<body>
  <div class="container">
    {% block content %}
      {{ content }}
    {% endblock %}
  </div>
<script src="{% static 'cms/js/jquery-3.3.1.min.js' %}"></script>
<script src="{% static 'cms/js/bootstrap.bundle.min.js' %}"></script>
{% block extra_js %}{% endblock %}
</body>
</html>
```
では、この`base_html`を継承して`mybook/cms/templates/cms/book_list.html`を作成する。

```book_list.html
{% extends "cms/base.html" %}

{% block title %}書籍の一覧{% endblock title %}

{% block content %}
    <h4 class="mt-4 border-bottom">書籍の一覧</h4>
    <table class="table table-striped table-bordered">
      <thead>
        <tr>
          <th scope="col">ID</th>
          <th scope="col">書籍名</th>
          <th scope="col">出版社</th>
          <th scope="col">ページ数</th>
        </tr>
      </thead>
      <tbody>
        {% for book in books %}
        <tr>
          <th scope="row">{{ book.id }}</th>
          <td>{{ book.name }}</td>
          <td>{{ book.publisher }}</td>
          <td>{{ book.page }}</td>
        </tr>
        {% endfor %}
      </tbody>
    </table>
{% endblock content %}
```
ブラウザで確認してみる。
データがないのでヘッダーのみ。

```
http://127.0.0.1:8000/cms/book/
```
<img width="1194" alt="スクリーンショット 2019-12-29 21.01.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472784/fffb536a-744d-9695-4c78-526ebd6fa973.png">

# 終わりに
とりあえず HTML を表示するところまでできた。
あとは`views.py`から API を呼び出して実行できれば目的が達成できる。
Python のフレームワークは初めて使用したが、躓く事なく表示するところまで進める事ができた。