Python Django チュートリアル(1)


勉強会用資料です．
django1.8のチュートリアルを辿りつつ説明していきます．
https://docs.djangoproject.com/en/1.8/intro/tutorial01/


日本語の公式ドキュメントはバージョン1.4が最新なので若干違いが有りますが大まかな流れは一緒なので一読するのもいいと思います．
http://django-docs-ja.readthedocs.org/en/latest/intro/tutorial01.html

公式サイトの説明ではプロジェクト名が`mysite`になっていますが，
`tutorial`プロジェクトとして作成していきます．

追記（2015/11/18）：[チュートリアルのチュートリアル](http://qiita.com/maisuto/items/d7e8cf0b5649f545ddb6)を作成しました．
→ [チュートリアルまとめ](http://qiita.com/maisuto/items/17653f344d1f64afa019)

## 環境
OS：Mac OSX10.11
python：3.4.2
django：1.8.5

## ソースコード

githubにチュートリアルのソースコードを置いておきます．
要所要所にtagを付け，できるだけ細かくコミットしていきますので参考にしてください．
https://github.com/usa-mimi/tutorial

## ファイル構成

こんなファイル構成で進めていきます．

```
tutorial/  # gitでcloneした際にできるディレクトリ
    ├ .git/
    ├ .gitignore
    ├ ...
    └ tutorial/  # 説明は特に注釈がない限りここをrootとして説明します
          ├ manage.py  # djangoのコマンドを実行する時に指定する
          ├ ...
          └ tutorial/
                ├ ...
                ├ urls.py  # projectのURL
                └ settings.py  # projectの設定ファイル
```
トップのtutorialディレクトリをgitの対象にしてます．
git用のREADMEやdeploy用の設定などdjango本体に関係ないファイルを置くためにこうしてます．

このディレクトリ内で
`(tutorial) $ django-admin startproject tutorial`
このコマンドを実行すると
tutorial/tutorial以下のファイル，ディレクトリが自動で生成されます．

gitで`project_start`タグをつけているのが上記コマンドを実行した直後の状態です．

ここからは特に注釈のない場合<b>`tutorial/tutorial`</b>を基準として説明していきます．

### 自動作成されるファイルの説明

https://docs.djangoproject.com/en/1.8/intro/tutorial01/#creating-a-project

#### ./manage.py
コマンドラインで色々な操作をする時に指定するファイルです．
サーバの起動やDBのmigrate，自作コマンドの実行などを行う場合はこのファイルにコマンドを渡して実行させます．

`$ python manage.py runserver`
`$ python manage.py migrate`
こんな感じです．

`manage.py`は実行権限がついているので
`$ python manage.py` のかわりに `$ ./manage.py ` と書くこともできます．

引数を何も渡さない場合は実行できるコマンド一覧が表示されます．
もっと詳しく知りたい方は公式サイトを参考にしてください．
https://docs.djangoproject.com/en/1.8/ref/django-admin/


実行して以下のような出力された方は`django`がinstallされてません．
仮想環境を作成しdjangoをinstallするか，`workon` コマンドで仮想環境に入ってください．

```
$ ./manage.py
Traceback (most recent call last):
  File "./manage.py", line 8, in <module>
    from django.core.management import execute_from_command_line
ImportError: No module named django.core.management
```

#### tutorial/settings.py
プロジェクトの設定ファイルです．
有効にするアプリやミドルウェア，
DB接続設定や各種ディレクトリなど諸々を設定します．

設定項目を詳しく知りたい方は公式サイトを参考にしてください．
https://docs.djangoproject.com/en/1.8/topics/settings/

#### tutorial/urls.py
サーバのURL設定です．requestされたURLを見てどのview（後述）でresponseを返すかはこのファイルに書きます．
settings.pyの中でROOT_URLCONFとして指定されてます．

公式説明→https://docs.djangoproject.com/en/1.8/topics/http/urls/


## データベースの作成

ドキュメント→https://docs.djangoproject.com/en/1.8/intro/tutorial01/#database-setup
ソース→`project_start`タグ

### データベースの設定

チュートリアルに習って次はデータベースの作成をしてみましょう．
どのDBを使うかは設定ファイル（`tutorial/settings.py`）に記述されています．
設定ファイルを開いて77行目付近を見てみてください．

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

デフォルトでは上記の用に`sqlite3`を使うようになっており，manage.pyと同じディレクトリに
`db.sqlite3`という名前のDBファイルを使うことになっています．
sqliteエンジンの場合はNAMEがsqliteファイルへのpathになります．
BASE_DIRはmanage.pyが置いてあるディレクトリを指してます．
`os.path.join` はシステムに応じたセパレータでパスを連結してくれる関数です．

mysqlサーバやpostgresqlサーバを使いたい人はこのファイルを以下のように書き換えてください．

```python
# mysqlサーバ
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'mydatabase',
        'USER': 'mydatabaseuser',
        'PASSWORD': 'mypassword',
        'HOST': '127.0.0.1',
        'PORT': '3306',
    }
}
```

```python
# postgresqlサーバ
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'mydatabase',
        'USER': 'mydatabaseuser',
        'PASSWORD': 'mypassword',
        'HOST': '127.0.0.1',
        'PORT': '5432',
    }
}
```

#### 補足：sqlite
> sqliteはデータベースをファイルで管理する簡易的なデータベースです．
サーバを用意する必要がなく，データベースの削除もファイルを消すだけで簡単にできるのでプロトタイプ作成には非常に向いています．
しかし通常のDBサーバに比べてアクセスが遅く，同時アクセス時にトラブルになりがちなので
完成したプログラムを動かす際は`mysql`や`postgresql`を使うようにしましょう．
macの場合は標準でインストールされていますが，windowsの場合は手動でインストールする必要があるようです．

> インストールの参考サイトのURLを貼っておきますので参考にしてください．
http://www.dbonline.jp/sqliteinstall/install/index1.html


### データベース作成

データベースの設定を終えたら実際にデータベースを作成（テーブル追加）しましょう．
データベース作成のコマンドは`migrate`です．
`$ ./manage.py migrate`

mysqlやpostgresqlを使う場合は予め空のデータベースを用意して上げる必要があるかもしれません．
sqlite3を使う場合は何も考えず．コマンドを実行するとファイルが作成されます．

特に設定を弄らずにコマンドを実行すると認証に使用するユーザ情報やセッション情報を保存するためのテーブルが作成されます．


```bash
$ ./manage.py migrate
Operations to perform:
  Synchronize unmigrated apps: messages, staticfiles
  Apply all migrations: contenttypes, auth, sessions, admin
Synchronizing apps without migrations:
  Creating tables...
    Running deferred SQL...
  Installing custom SQL...
Running migrations:
  Rendering model states... DONE
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... 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 sessions.0001_initial... OK
```

#### 補足：syncdb
> django1.6までは`syncdb`というコマンドを使ってデータベースの初期化を行っていました．
このコマンドを実行すると`migrate`コマンドと，次に説明する`createsuperuser`コマンドを
続けて実行するような動きになります．
django1.8の時点でもコマンドは残っていて実行できますが，django1.7から公式では非推奨になっています．

> 日本語ドキュメントはdjango1.4のため`syncdb`で説明されていると思いますのでご注意ください．

## サーバ起動確認
ドキュメント→https://docs.djangoproject.com/en/1.8/intro/tutorial01/#the-development-server
ソース→`project_start`タグ

### ブラウザで確認

djangoフレームワークにはサーバ機能もついており，開発時に専用のサーバを用意する必要がありません．
実行するコマンドは`runserver`です．
実行するとデフォルトでは8000番ポートを使用して開発用サーバが起動します．
この状態でブラウザで http://localhost:8000/ にアクセスすることで動作確認ができます．

```bash
$ ./manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).
October 31, 2015 - 08:55:38
Django version 1.8.5, using settings 'tutorial.settings'
Starting development server at http://127.0.0.1:8000/  # ← 起動時のアドレス
Quit the server with CONTROL-C.
[31/Oct/2015 09:06:54] "GET / HTTP/1.1" 200 1767  # ← ブラウザでアクセスした時に表示される
```

![Kobito.uICdzG.png](https://qiita-image-store.s3.amazonaws.com/0/58048/24648307-e884-48dd-e21a-7ed3312300bb.png "Kobito.uICdzG.png")
何も作ってないからデフォルト画面が表示される．


>ポート番号を変更したい場合は
`$ ./manage.py runserver 8080` のようにポート番号を引数に与えます．
同じLAN内にあるPCからアクセスしたい場合は
`$ ./manage.py runserver 0.0.0.0:8000` のように書いとくと
同じLAN内からアクセスできるようになります．
マシンのIPは`ipconfig`や`ifconfig`などのコマンドで調べてください．

#### 補足：runserverの自動読み込み
> runserverで起動中にプログラムを変更したらdjangoは自動的に再起動してくれます．
runserverしているターミナルを持ってきて一度停止して起動... なんてことはする必要ありません．
ただ，新しいテンプレートディレクトリを追加した場合など，自動で読み込まれないこともあるので少しだけ注意しましょう．


## アプリ追加
ドキュメント→https://docs.djangoproject.com/en/1.8/intro/tutorial01/#creating-models
ソース→ `start_project`タグ → `add_app_4_database_migration`タグ

いよいよアプリケーションを追加していきます．
チュートリアルでは`polls`という投票アプリを例にとり，モデルの作成方法を説明しています．

その前にdjangoでアプリケーションを使いする流れについて説明しておきます．

1. `$ ./manage.py startapp appname` でアプリケーションを追加する．

2. `appname/models.py` にそのアプリで使用するモデル（データベースのテーブル）を記述する．

3. `project/settings.py`に作成したアプリを追加する

4. データベース更新

5. `appname/views.py` にモデルの表示や操作（追加，編集など）を記述する．
使用するhtmlもここで用意．
6. `appname/urls.py` を記述し，urlとviewsを紐付ける
7. `project/urls.py`から`appname/urls.py`を読み込む．

1から4まではこのチュートリアルで行います．
5以降はチュートリアル3で説明します．
（チュートリアル2は「管理画面」の話です）
ソースのタグは`add_app_x`の形式で付けています．

### 1. pollsアプリ追加

manage.pyのstartappコマンドを実行しましょう．
アプリ名のついたディレクトリといくつかのファイルが自動的に作成されます．


```bash
$ ./manage.py startapp polls
$ tree polls
polls
├── __init__.py
├── admin.py  # 管理サイト絡みのファイル
├── migrations  # 自動生成されるので特に触らない
│   └── __init__.py
├── models.py  # テーブル情報や動作を記述していくファイル
├── tests.py  # testを書きたい場合はこのファイルを編集する
└── views.py  # requestを受け取りresponseを返す関数を追加していく
```

> チュートリアル3では，これに加えて`forms.py`, `templates/`, `urls.py`を手動で追加します．


### 2. モデルの記述

チュートリアルにならって`polls/models.py`を書き換えましょう．
`models.Model`クラスを継承して作ったクラスはDBのテーブルを表すクラスになります．
`models.~Field`インスタンスを使用して設定するプロパティはテーブルのカラムを表現します．
プロパティ名がそのままテーブルのカラム名になります．
チュートリアルでは`Question`テーブルと`Choice`テーブルを設定しています．

```python:polls/models.py
 from django.db import models


class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')


class Choice(models.Model):
    question = models.ForeignKey(Question)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)
```

#### 補足：Model
> 今回のチュートリアルでは出てきませんが，Metaクラスを設定することでクラスの振る舞いを色々と調整できます．
ドキュメント→https://docs.djangoproject.com/en/1.8/ref/models/options/

> データ取得時のデフォルトの並び順を指定したり，作成されるテーブルの名前を変更することができます．
>>デフォルトでは`appname_modelname`のテーブルが作成されます．
チュートリアルの例では`polls_question`, `polls_choice`のテーブルが作成されます．
特別な理由がない限りテーブル名の変更はオススメしません．

> 他の有用な設定項目としては次のチュートリアルで説明する管理ページでの名前の変更や，
複数fieldのunique制約の設定（例えば`日付`と`項目`で制約を掛ける）などです．

> 記述方法は以下の様な感じです

```python
class Question(models.Model):
    class Meta:
        app_label = 'polls'
        verbose_name = '質問'
        table_name = 'polls_question'
```

#### 補足：Field
> どんな種類のFieldがあるかは本家のドキュメントを参考にしてください．
ドキュメント→https://docs.djangoproject.com/en/1.8/ref/models/fields/#field-types

> 一般的なDBのカラム型に相当するものは網羅されているはずです．
fieldにはいくつかの共通のオプションの他に，フィールド独自のオプション，必須項目を持っています．
例えば`CharField`は一般的なDBのchar型を表現します．
char型は文字数の指定が必須であるため，djangoの`CharField`も`max_length`引数が必須となっています．

> `ForeignKey`は少し特殊なFieldで，他モデルへのリレーションを表現します．
カラム型はリレーションを貼ったモデルの主キーと同じ型になり，カラム名はプロパティ名に`_id`が追加されたものになります．
チュートリアルの例では，question_idという名前のinteger型のカラムが作成されます．
（デフォルトの主キーがinteger型のため）

> 同ファイル内で定義されているモデルへのリレーションのため，引数に直にクラスを渡していますが，
別ファイルで定義されているモデルへリレーションを貼りたい場合は`app.model`の形式で文字列でリレーションを張るモデルを指定します．
> 例：`question = models.ForeignKey('polls.Question')`

### 3. アプリケーションの追加
ドキュメント→https://docs.djangoproject.com/en/1.8/intro/tutorial01/#activating-models


`startapp`でアプリを追加しただけではそのアプリケーションは有効化されません．
`tutorial/settings.py`の中に使用するアプリ一覧の項目があるので，そこに作成したアプリを追加しましょう．
設定するための変数はsettings.pyの33行目付近にある`INSTALLED_APPS`という名前のタプルです．

```python:tutorial/settings.py
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'polls',  # ← これを追加
)
```

今回は自作した`polls`アプリを追加しましたが，`pip`などで出来合いのdjangoアプリケーションを追加する場合も同様にINSTALLED_APPSにアプリ名を追加しましょう．
ここに追加するとmigrationやtemplates，testなどの読み込み対象になります．

### 4. データベース更新
ドキュメント→https://docs.djangoproject.com/en/1.8/intro/tutorial01/#activating-models
（`3. アプリケーションの追加`と同じ）

settings.pyを変更したら`makemigrations`コマンドを実行しましょう．
このコマンドは各アプリのmodelの変更を検出し，自動でmigrationファイルを作成してくれます．
このコマンドを実行してmigrationファイルを作った後に，migrateコマンドを実行することで
DBへモデル(=テーブル)の変更を反映させます．


```bash
$ ./manage.py makemigrations
Migrations for 'polls':
  0001_initial.py:
    - Create model Choice
    - Create model Question
    - Add field question to choice
```
> 変更があったら自動的で検出してmigrationファイルが作成されます．
今回はテーブルの追加なのでありませんが，フィールドの追加時にdefault値を設定していない場合は
defalt値を何にするかを聞かれます


```bash
$ ./manage.py migrate
Operations to perform:
  Synchronize unmigrated apps: messages, staticfiles
  Apply all migrations: admin, auth, polls, contenttypes, sessions
Synchronizing apps without migrations:
  Creating tables...
    Running deferred SQL...
  Installing custom SQL...
Running migrations:
  Rendering model states... DONE
  Applying polls.0001_initial... OK
```
> migrateコマンドを実行することでdatabaseに設定が反映されます．
どのmigrateコマンドを実行したかは`django_migrations`テーブルに記録されています．

--
本家のチュートリアルではこの後でモデルのカスタマイズ，シェルでの実行を行っていますが，
本チュートリアルでは割愛します．
モデルのカスタマイズについては次のチュートリアルで説明します．
https://docs.djangoproject.com/en/1.8/intro/tutorial01/#playing-with-the-api

--
[次のチュートリアルへ](http://qiita.com/maisuto/items/357d13027e4fe5e10618)

→ [チュートリアルまとめ](http://qiita.com/maisuto/items/17653f344d1f64afa019)