Django×PinaxでWebサービス入門②｜ローカルでアプリを動かす

## この記事の内容
この記事では、Django製のWebアプリケーションを作り、自分のローカルPCでブラウザからつないで見るところまで進めます。
（ずっとターミナルでコマンドを打ち込み、いろいろインストールしたり何かを自動で構築したりということが進みます）

全体像で見てみると、この緑色で囲った部分が対象です。

![Overall Structure_01.png](https://qiita-image-store.s3.amazonaws.com/0/113133/2a5e9fdd-53bc-7a88-b67b-0d3a3c50332c.png)

<details><summary>ターミナルとは</summary><div>
ターミナルはMacで標準搭載されている、コンピューターに直接命令（コマンド）をうちこむアプリです。黒い画面（デフォルトは白ですが）にひたすら文字が流れていくあれです。
Finderで アプリケーション > ユーティリティ > ターミナル から起動できます。
</div></details>

- Homebrewのインストール
- Python3のインストール
- Virtualenvで仮想環境を作る
- Django（Pinax）を使ってWebアプリケーションを構築
- npmでフロント周りの静的ファイルを生成

ということをやっていきます。

## Homebrewのインストール
後ほどPython3をインストールするのですが、そのためにHomebrewというMacOS用のパッケージマネージャーが必要になるので、それを先にインストールします。コマンドは[公式サイト](https://brew.sh/index_ja)通りです。

```terminal:
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```
<details><summary>ターミナルにコマンドをコピペするとき</summary><div>
上記のようなコマンドをターミナルに貼り付けて実行するということが頻繁に起きます。
その時に`#`もしくは`$`という文字のあとにコマンドが書かれていても、そられは除いてコピペしてください。これは管理者ユーザー（rootユーザー）でログインしているか一般ユーザーログインしているかを表すために慣例的に記載しているものです。
（参考）[【完全初心者向け】Linuxのrootユーザとは？](https://eng-entrance.com/linux-root)
</div></details>

<details><summary>パッケージマネージャーとは</summary>
何かを作るときは、いろいろなパッケージ（ライブラリ）を駆使しながら進めていきます。その時にそれらパッケージ（ライブラリ）を簡単にインストール・アップデート・アンインストールできるようにする管理ツールが必要になってきて、このことをパッケージマネージャー（パッケージ管理）と呼びます。
Homebrewの他にも、Pythony用パッケージマネージャーのpip、CentOSで使うyumなど様々なものがあります。
</details>

## Python3のインストール

Pythonのバージョンは2系と3系で構文の書き方が違ったり利用できるライブラリが異なったりします。そのため目的に応じてPythonのバージョンを使い分けられる必要がででき、アプローチとしては、

- 元々macに入っている2系に加えて3系をインストールして、別々のコマンドで使い分けるという方法 (今回はこちらで説明します。)
- pyenvという複数バージョンのPythonを簡単に切り替えることができるライブラリを用いる方法

があります。

MacにはPython2系が予めインストールされています。それを確認してみましょう。

```terminal:
$ python -V

Python 2.7.10
```
どこにインストールされているかも見てみます。

```terminal:
$ which python

/usr/bin/python
```
それでは、Python3系をHomebrewでインストールします。

```terminal:
$ brew install python3
```
これで最新版のPython3が入ります。バージョンとインストール先を確認します。

```terminal:
$ python3 -V

Python 3.6.5

$ which python3

/usr/local/bin/python3
```

## Virtualenvで仮想環境を作る
続いて、VirtualenvというPythonの仮想的な環境を作るためのパッケージを使って、今回作成するTODOアプリ専用の環境を作成します。
例えば2つのPython製アプリケーションを開発している場合に、一方は特に制約なく最新バージョンのPythonを利用できる、しかしもう片方は最新バージョンのPythonに対応していないライブラリを利用しないといけない、といったことがあります。
こういった場合に、Pythonのバージョンやインストールしたライブラリ群が異なる環境をわけて作ることで、2つのアプリを共存させられるようになります。

まず、VirtualenvをpipというPython用のパッケージマネージャーを使ってインストールします。

```terminal:
$ pip install virtualenv
```
そして、これから作成してくTODOアプリのための作業ディレクトリを作成します。

```terminal:
$ mkdir todo
```
作成したディレクトリに移動します。

```terminal:
$ cd todo
```

virtualenvのコマンドで先ほどインストールしたPython3を指定して環境を作成します。
はじめにhomebrewでPython3をインストールした際にコマンドのパスが通ったので、そのコマンドを利用してPythonのバージョンを指定します。

```terminal:
$ virtualenv -p python3 todo_env
```
これで`todo_env`という名前のTODOアプリ専用の仮想環境ができました。これを起動します。

```terminal:
$ source todo_env/bin/activate
```
ターミナルでユーザー名の頭に`(todo_env)`というものが付いたと思います。これが仮想環境の中にいるということを意味しています。
それでは、さっきと同様にPythonのバージョンを確認してみます。

```terminal:
$ python -V

Python 3.6.5
```
さきほどインストールしたPython3系が利用されています。

ここまでで何を作ったのかは下図のような感じです。

![00.png](https://qiita-image-store.s3.amazonaws.com/0/113133/b461b51e-5cc1-5fbc-1b7d-0500435d5ed0.png)

MacOSにはPython2とPython3を別々にインストールし、それぞれ`python`、`python3`というコマンドで呼び出せるようにしました。そして`todo_env`という仮想環境を作るときに、Python3の方を利用するように指定しました。
なので図のようにこの他にも仮想環境を作り、適したバージョンのPythonを適用することができます。

なお、この仮想環境を終了する場合は`deactivate`コマンドを使います。

```terminal:
$ deactivate
```
## Django（Pinax）を使ってWebアプリケーションを構築
ようやくDjangoを使ってWebアプリケーションを作っていきます。ここでDjangoとPinaxに関して軽く触れます。

### Django
DjangoはPython製のWebフレームワークです。2005年にリリースされたもので結構歴史が長く、Python製Webフレームワークの中ではかなり有名です。
[The Top Web Development Frameworks in 2018](https://expertise.jetruby.com/the-top-web-development-frameworks-in-2018-b31dc7263875) によると、

1. Djangoは早い開発スピードを実現する
2. Djangoはセキュリティ面に優れている
3. Djangoはスケーラブルで、トラフィックの増加に対応しやすい
4. Djangoは全ての機能が搭載されている

と書かれています。デフォルトの機能、また様々なDjango用のライブラリが豊富だったりDjangoプロジェクトがあるため、こんなことをやりたいというときにはかなりサクサク要望を実現できます。
例えば『スマホアプリでも利用できるようにしたいのでAPIを作りたい』といったものや、『Q&Aページを作ってユーザーの問い合わせを効率的に管理したい』といったものなど探すと結構出てきます。

<details><summary>Webフレームワークとは</summary><div>
Webアプリケーションを作るときには、クライアント（普段使うPCとかスマホ）からリクエスト（このページを見せて）を受け、それに応じてデータベースを呼び出して情報を取る機能や、データベースにどんな情報を蓄積するか管理する機能、さらにレスポンス（HTML）を作ってクライアントに返す機能などが求められます。Webフレームワークとはこれらの機能を用意しておいて、Webアプリケーションを開発しやすくしたものです。
</div></details>

### Pinax
Pinaxは有志が作っているDjango製のアプリケーションの雛形で、Webでよく使われる機能があらかじめ含まれたプロジェクトです。これを使ってDjangoのWebアプリケーション開発を始めることで、かなり効率的に進められるようになります。

[Pinax本家サイト（英語）](http://pinaxproject.com/pinax/)

ものを見たほうが早いので、実際に使っていきます。

まず、Pinaxのコマンドラインインターフェイスをpipでインストールします。

```terminal:
$ pip install pinax-cli
```
これでpinaxのプロジェクトを利用する準備ができました。どんなプロジェクトがあるか見ていきます。

```terminal:
$ pinax projects

Release Project
------- ---------------
  4.0.4 account
  4.0.4 blog
  2.0.4 company
        documents
        social-auth
  4.0.4 static
  4.0.4 stripe
        team-wiki
  3.0.4 waitinglist
        wiki
  4.0.4 zero
```
利用可能なプロジェクトの一覧が表示されています。ここで言うプロジェクトの実のところは、作りたいWebアプリケーションごとに必要な機能が用意されたDjangoプロジェクトです。いくつか見ていくと、

- account : 会員管理系のサイト用プロジェクトです。会員登録・ログイン・ログアウト・退会といった機能があります。
- wiki : wikiサイト用のプロジェクトです。権限を受けたユーザーがwikiページを投稿できるといった機能があります。
- stripe : 課金サービス系のサイト用プロエクとです。決済サービスのstripeと連携する機能があります。

などがあります。もっと詳しくは [Pinax Starter Projects] (http://pinaxproject.com/pinax/pinax_starter_projects/#starter-project-list) を御覧ください。

今回はオーソドックスな`account`を利用します。アプリケーションの名前は`todo`とします。

```terminal:
$ pinax start account todo
```
TODOアプリのプロジェクトが生成されたので、ディレクトリの中に入ります。

```terminal:
$ cd todo
```

このプロジェクトを動かすためのライブラリを今の仮想環境にインストールします。インストールが必要なライブラリはこのディレクトリの中にある`requirements.txt`というファイルに定義されています。

```terminal:
$ pip install -r requirements.txt
```
どんなものがインストールされたのか見てみます。

```terminal:
$ pip list

Package               Version  
--------------------- ---------
certifi               2018.4.16
chardet               3.0.4    
click                 6.7      
colorama              0.3.9    
crayons               0.1.2    
Django                2.0.6    
django-appconf        1.0.2    
django-bootstrap-form 3.4      
django-user-accounts  2.0.3    
idna                  2.6      
jsonfield             2.0.2    
pinax-cli             1.1.4    
pinax-eventlog        2.0.3    
pinax-templates       2.0.1    
pinax-webanalytics    4.0.2    
pip                   10.0.1   
pytz                  2018.4   
requests              2.18.4   
setuptools            39.2.0   
urllib3               1.22     
wheel                 0.31.1 
```

`Django`やユーザー管理用の`django-user-accounts`がインストールされているのがわかります。

次に、このアプリケーションで使うデータベースのテーブルを作ります。
なお、ここから`manage.py`というファイルを経由してコマンドを実行していきます。これらは全てDjangoが用意しているコマンドです。

```terminal:
$ python manage.py migrate

Operations to perform:
  Apply all migrations: account, admin, auth, contenttypes, eventlog, sessions, sites
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying account.0001_initial... OK
  Applying account.0002_fix_str... OK
  Applying account.0003_passwordexpiry_passwordhistory... OK
  Applying account.0004_auto_20170416_1821... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying eventlog.0001_initial... OK
  Applying eventlog.0002_auto_20150113_1450... OK
  Applying eventlog.0003_auto_20160111_0208... OK
  Applying sessions.0001_initial... OK
  Applying sites.0001_initial... OK
  Applying sites.0002_alter_domain_unique... OK
```

ここで行ったのは『マイグレーション』という処理です。Djangoには`Model`というデータベースの定義を『マイグレーションファイル』として作成して、それのファイルをもとにその定義のテーブルを作るという機構があります。
なのでここでは`account`プロジェクトで定義されていたファイルを読み込んで、テーブルが生成されました。

今はまだテーブルにデータが入っていない状態ですが、次のコマンドで最低限のサイト情報を取り込みます。

```terminal:
$ python manage.py loaddata sites
```

`fixtures/sites.json`の定義を基にデータをロードする処理が行われ、データが作られました。

今作られたデータを見てみたいので、管理画面にログインするために管理者用のアカウントを作ります。これもDjangoに予め用意されている機能が利用できます。
ここでは任意の`Username`、`Email address`、`Password`を入力します。
今回は`Username`は`user`とし、`Email address`は必須ではないので未入力で進めます。

```terminal:
$ python manage.py createsuperuser

Username (leave blank to use 'user'): user
Email address: 
Password: 
Password (again): 
Superuser created successfully.
```

<details><summary>パスワードは表示されません</summary><div>
ここでは`Password`はキーを入力しても何も表示されませんが、セキュリティに配慮してなので実際は入力できています。
</div></details>

サーバーを起動します。
Djangoには開発用のサーバーが用意されているので、わざわざApacheなどWebサーバーを立てなくても動作の確認ができます。

```terminal:
$ python manage.py runserver

Performing system checks...

System check identified no issues (0 silenced).
June 03, 2018 - 07:20:28
Django version 2.0.6, using settings 'todo.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
```

サーバーが起動されました。ブラウザから`http://localhost:8000/admin/login/?next=/admin/`にアクセスしてみます。

![Log in I Django site admin - http___localhost_8000_admin_login__next=_admin_.png](https://qiita-image-store.s3.amazonaws.com/0/113133/99858866-5eb1-e9b4-00b5-ffa52dd02f0c.png)

管理画面にアクセスできました。この管理画面はDjangoの特徴の一つで、データベースに接続しなくてもブラウザからデータの閲覧・作成・編集・削除ができるものです。
実際に処理が反映されたかどうか、データベースを見に行くみたいな手間が省けてかなり良いです。

先程登録した`user`とパスワードでログインすると、このアプリケーションで管理している情報を見ることができます。一番下にある`Sites`というリンクから`http://localhost:8000/admin/sites/site/`にアクセスすると、サイトのレコードが2つ登録されてるのがわかると思います。これが先程`loaddata`コマンドで作成したデータです。

![Select site to change I Django site_ - http___localhost_8000_admin_sites_site_.png](https://qiita-image-store.s3.amazonaws.com/0/113133/e020d01c-5e6b-b7d1-3762-513155eb6f31.png)

なお、`runserver`コマンドを叩いたときに`http://127.0.0.1:8000/`でサイトが見れますというふうに言われるのですが、このタイミングだと`localhost`しか受け付けない設定になっているのと、CSSやjsなどフロント周りの静的ファイルを生成していないので`http://localhost:8000/`にアクセスしても見た目がくずれている状態です。

一旦`Ctrl+C`でサーバーを停止して次に進みます。

※もし違うコマンド（`Ctrl+Z`）やターミナル自体を閉じてしまうと、サーバーは起動したままになります。そんなときは`lsof`コマンドでポート番号からプロセスを探して、`kill`コマンドでプロセスを終了できます。

```terminal:
$ lsof -i :8000

COMMAND     PID USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
python3.6 12685 user    6u  IPv4 0x581221ac75463bd3      0t0  TCP localhost:irdmi (LISTEN)

$ kill -9 12685
```

## npmでフロント周りの静的ファイルを生成

ということで、最後にフロントまわりの静的ファイルを生成します。
PinaxではCSSやjsなどのファイルを管理するためにnpmという技術を利用しているので、npmを使って静的ファイルを生成するところまで進めます。流れとしては、

1. nodebrew（nodeのバージョン管理ツール）をインストール
2. Node.jsとnpm（Node.js製のパッケージマネージャー）をインストール

です。またバージョンとかパッケージマネージャーとかが出てきて辟易とするかもしれませんが、一度入れてしまえば便利な技術です。
先程はPython2とPython3を別々に入れたのでしっかりと扱いませんでしたが、nodeのバージョン管理ツールであるnodebrewのように、Pythonのバージョン管理ツールであるpyenvというものもあります。

では一番最初にインストールしてMacOS全体のパッケージマネージャーであるHomebrewを利用して、nodebrewをインストールします。

```terminal:
$ brew install nodebrew
```

nodebrewのバージョンを見てみます。

```terminal:
$ nodebrew -v
nodebrew 1.0.0
```

そして、`setup`コマンドで設定周りの指示を受けます。

```terminal:
$ nodebrew setup

Fetching nodebrew...
Installed nodebrew in $HOME/.nodebrew

========================================
Export a path to nodebrew:

export PATH=$HOME/.nodebrew/current/bin:$PATH
========================================
```

パスを通すように書いてあるので、上記で表示されたコマンドを実行します。

```terminal:
$ export PATH=$HOME/.nodebrew/current/bin:$PATH
```

nodebrewは複数バージョンのNode.jsを管理するので、インストール→どれを利用するか指定するという流れになります。今回は`v9.3.0`を使います。
（安定版の`v10.3.0`を試しましたが、pinaxが対応していないようでした。）

```terminal:
$ nodebrew install-binary 9.3.0
```

インストールされたバージョンを見てみます。

```terminal:
$ nodebrew list

v9.3.0

current: none
```

まだ`current: none`なので、どのバージョンも指定されていません。今インストールしたバージョンを指定します。

```terminal:
$ nodebrew use 9.3.0

use v9.3.0
```

すると、node.jsとnpmが使えるようになります。

```terminal:
$ node -v

v9.3.0

$ npm -v

5.5.1
```

ようやくWebアプリケーションの方に戻ることができます。最初に今いる同一階層にある`package.json`というファイルの定義に従って必要なパッケージをインストールします。

```terminal:
$ npm install
```

続いて、Pinaxで用意されているcssファイルとjsファイルを生成します。

```terminal:
$ npm run dev
```

すると、`static/dist/`配下に静的ファイルが生成され、先程シャットダウンした開発用サーバーが起動しました。
ここで`http://localhost:8000/`にアクセスすると、見た目がちゃんとしたトップページが表示されます。

![example.com [localhost] I pinax-project-account - http___localhost_8000_.png](https://qiita-image-store.s3.amazonaws.com/0/113133/3812ce69-aeec-5702-7e26-5b4731da20bd.png)

Bootstrap4を使っていて、整っています。
会員登録やログイン・ログアウト、登録情報の変更、退会などもできるので試してみてください。

ちなみに、このnpmの定義ファイル`package.json`は大まかにnpmでどのようなライブラリを管理するか、そしてどのようなscriptの処理を持つかを司っています。このscriptの部分を見ると、下記のようになっています。

```json:
"scripts": {
    "clean": "rm -rf static/dist && mkdir -p static/dist/js && mkdir -p static/dist/css && mkdir -p static/dist/images",
    "build:js": "browserify -t [ babelify --presets [ env ] ] -t envify -o static/dist/js/site.js static/src/js/index.js",
    "build:css": "node-sass static/src/scss/index.scss static/dist/css/app.css",
    "copy:images": "cp -r static/src/images/* static/dist/images/ 2>/dev/null || :",
    "optimize:js": "uglifyjs static/dist/js/site.js -m -c warnings=false -o static/dist/js/site.js",
    "optimize:css": "cssnano static/dist/css/app.css static/dist/css/app.css",
    "optimize": "npm run optimize:js && npm run optimize:css",
    "watch:test": "onchange static/src/js/**/*.js -- npm run test",
    "watch:lint": "onchange static/src/js/**/*.js -- npm run lint",
    "watch:js": "watchify -t [ babelify --presets [ env ] ] -t envify static/src/js/index.js -o 'exorcist static/dist/js/site.js.map > static/dist/js/site.js' -dv",
    "watch:css": "node-sass static/src/scss/index.scss static/dist/css/app.css --watch -r",
    "build": "npm run clean && concurrently \"npm run build:js\" \"npm run build:css\" \"npm run copy:images\" && npm run optimize",
    "watch": "npm run clean && npm run copy:images && npm run build:css && concurrently --raw \"npm run watch:lint\" \"npm run watch:js\" \"npm run watch:css\"",
    "dev:browser-sync": "browser-sync start --no-open --proxy localhost:8000 --files \"static/dist/js/*.js, static/dist/css/*.css\"",
    "dev": "concurrently --raw \"./manage.py runserver\" \"npm run watch\" \"npm run dev:browser-sync\"",
    "lint": "eslint static/src/**/**/*.js",
    "test": "mocha --recursive --compilers js:babel-register static/src/tests/index.js",
    "compile": "NODE_ENV=production npm run clean && concurrently \"npm run copy:images\" \"npm run build:js\" \"npm run build:css\"",
    "heroku-postbuild": "npm run compile && npm run optimize"
},
```

この中にある `dev` というのが、`npm run dev`というコマンドを叩いたものです。これを見ると、

- `manage.py runserver` : Webサーバーを起動してアプリケーションにローカルでアクセスできるようにする(先程叩いたコマンドです。)
- `npm run watch` : scssファイルに変更があったときに、変更を検知してcssファイルを更新する。
- `npm run dev:browser-sync` : 静的ファイルが更新されると、ブラウザをリロードする

という3つのコマンドが内包されているのがわかります。
このあとでIDE（統合開発環境）であるPyCharmを使っていきますが、その時は`npm run watch`を、またVPSにデプロイしたあともWebアプリケーションを動かすのはApacheの役割で`manage.py runserver`は必要ありません。そのためVPS上でも`npm run watch`のみを使うことになります。

## 次回

とまあコードを一行も書いていませんが、何やらできあがりました。
次回はPython用統合開発環境（IDE）であるPyCharmをセットアップし、Django製Webアプリケーションの開発を効率的に行うための土台を作ります。

[Django×PinaxでWebサービス入門③｜PyCharmをセットアップ](https://qiita.com/mtitg/items/270c422def5202d672a9)