Python Django入門 (3)


Djangoを始める
--------------

### ドキュメント

* [Django ドキュメント](https://docs.djangoproject.com/ja/3.0/) 

「何もないところから始めるなら：概要」と「チュートリアルはこちら：その１〜７」を一読するのがよいのですが、まずはこの講座を先にやってみてもよいでしょう。

* 基本的にコピペでOKです。
* どう動くのか、なんとなくわかったら、公式のチュートリアルをやってみて、理解を深めましょう。

Djangoで作ってみる
------------------

### プロジェクトの作成

簡単な書籍を管理するアプリを作成してみます。

まず、mybook というプロジェクトを作ります。これには `django-admin startproject mybook` というコマンドを使います。

> PyCharmで、お試しでプロジェクトを作ってみると、PycharmProjectsというフォルダができるようなので、その下に作ることにします

> (env1) の仮想環境にいることを確認して下さい。
> 既にいる場合は、以下のMacの `workon env1`、Windowsの `Scripts¥activate` は不要です。

Macの方は、

```bash
$ workon env1

(env1) $ cd ~/PycharmProjects/
(env1) $ django-admin startproject mybook
```

Windowsの方は、

```bash
C:¥Users¥hoge>cd Documents¥env1
C:¥Users¥hoge¥Documents¥env1> Scripts¥activate

(env1) C:¥Users¥hoge¥Documents¥env1> cd C:¥Users¥hoge¥PycharmProjects
(env1) C:¥Users¥hoge¥PycharmProjects> django-admin startproject mybook
```

ここから説明はMac前提に戻ります。
Windowsの方は、それぞれの環境に読み替えて下さい。

~/PycharmProjects/ にできたファイル

```bash
mybook/
    manage.py
    mybook/
        __init__.py
        asgi.py
        settings.py
        urls.py
        wsgi.py
```

mybook ディレクトリの中に移動して下さい。

```bash
$ cd mybook
```

### PyCharmでプロジェクトを開く

生成したプロジェクトをPyCharmで開いてみます。

1.Create New Project を選択します

![Welcome_to_PyCharm.jpg](https://qiita-image-store.s3.amazonaws.com/0/48136/179917a3-6cde-1a7f-f127-bef99faf2014.jpeg "Welcome_to_PyCharm.jpg")

2.左側で Django を選択します。

![New_Project_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48136/c14c54d0-fdfc-c5d8-14d8-e5cef59e322d.png "New_Project_01.png")

3.Location: 右側のフォルダ アイコンをクリックして、先程生成した mybook フォルダを選択します。

![New_Project_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48136/0533e15c-5c70-73be-4c8a-95dce83f048c.png "New_Project_02.png")

> Windowsの場合は、C:¥Users¥hoge¥PycharmProjects¥mybook になります。

4.Project Interpreter: の三角アイコンをクリックして展開し、Existing Interpreter の方の Interpriter の「...」 を選択します。

![New_Project_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48136/f26117f4-fc43-0ee7-3aba-22732f20b118.png "New_Project_11.png")

5.Virtualenv Environment > Interpreter の「...」を更に選択します。

![New_Project_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48136/9999f128-7da4-39d1-6504-ca4dea3aef7e.png "New_Project_12.png")

6.env1仮想環境のPython3を、Pythonインタープリターとして選択します

![New_Project_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48136/ffbb3ee1-c42c-9f4a-3b45-1e46bc9d43d1.png "New_Project_13.png")

> Windowsの場合は、C:¥Users¥hoge¥Documents¥env1¥python.exe になります。

7.OK で閉じます。

![New_Project_14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48136/606a74df-a676-721a-61d7-3ee5733a8085.png "New_Project_14.png")


8.Createボタンを押します（左が Djangoになっているかを再確認）

![New_Project_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48136/f1b52129-55a0-fefe-bab8-f2af48932851.png "New_Project_15.png")

9.既にあるけど、いいかと聞いてくるので、Yesと答えます

![New_Project_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48136/2366eb28-1112-c53e-3b01-0a941a53c993.png "New_Project_06.png")

10.このようにできたら成功です

![New_Project_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48136/1bad066b-3875-9f7f-e12f-62df50a1207d.png "New_Project_07.png")



### データベースのセットアップ

データベースの設定は、`mybook/settings.py` にありますが、標準では、SQlite3を使うよう設定済です。

```python
# 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'),
    }
}
```

`mybook/settings.py` を見たついでに、言語とタイムゾーンを日本にします。

> `#` はコメントアウトした行という意味です。コメントアウトするには、
> Macの場合は、行に位置付けて（複数行の場合は、行を選択して） command ＋ / です。
> Windowsの場合は Ctrl ＋ / です。
> うーん便利。

```python
# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'ja'

# TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Tokyo'
```

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

```bash

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... 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 auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying sessions.0001_initial... OK
```

以下のコマンドで、スーパーユーザーを作成します。

```bash
$ python manage.py createsuperuser
ユーザー名 (leave blank to use 'hoge'): admin
メールアドレス: admin@example.com
Password: hogefuga
Password (again): hogefuga
Superuser created successfully.
```

途中、以下の質問に答えます。

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

### 開発用サーバの起動

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

```bash
$ python manage.py runserver

Performing system checks...

System check identified no issues (0 silenced).
January 08, 2020 - 16:20:02
Django version 3.0.2, using settings 'mybook.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
```

ブラウザで http://127.0.0.1:8000/ にアクセスしてみます。

![dango01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48136/09397048-59d6-59b9-ca32-2d269de68475.png "dango01.png")

開発用サーバの終了は、`control + c` です。

### PyCharmでデバッグ実行する

画面の右上の虫マークを押すだけです。
もしくは、メニューの Run > Debug.. > mybook を選択します。

![debug.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48136/2c9b79c2-8d98-7175-25a4-6876bb369031.png "debug.png")

下にガバッと以下の様な表示が出ればOKです。
止めたい時は、赤い四角のボタンを押します。

![stop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48136/cd6c96dc-e50b-7195-92cc-47a3823dcc9f.png "stop.png")

一般的なIDEのように、コードの行番号の右側あたりをクリックすることで、ブレークポイントの設定や、変数の確認ができます。

止めたら、Debugウィンドウは邪魔なので、折り畳むボタンを押します。

![fold.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48136/940a012d-db74-3d32-b591-931b058b43ae.png "fold.png")


### アプリケーションの作成

プロジェクトの下に cms というアプリケーションを作成してみます。

cmsは、Contents management system、ようするにマスターメンテナンスのようなものとします。
アプリケーションは、プロジェクトを構成する機能の単位で、場合によっては再利用の対象とできる単位です。

以下のコマンドで作成します。

    $ python manage.py startapp cms


mybook プロジェクトのディレクトリの下に、以下のファイルが作成されました。

```bash
mybook/
    cms/
        __init__.py
        admin.py
        apps.py
        migrations/
            __init__.py
        models.py
        tests.py
        views.py
    manage.py
    mybook/
       :
       :
```

### モデルの作成

データベースに定義したいデータ モデルを、`cms/models.py` に定義します。

> classの前は、2行開けないと、波線が出て警告されます。pep8というコードスタイルチェックの仕組みです。
> 同様に、コードの最後が改行のみで終わっていないと、また波線が出て怒られるので、気をつけましょう。

```python
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


class Impression(models.Model):
    """感想"""
    book = models.ForeignKey(Book, verbose_name='書籍', related_name='impressions', on_delete=models.CASCADE)
    comment = models.TextField('コメント', blank=True)

    def __str__(self):
        return self.comment
        
```

`感想` は `書籍` に紐づく、子供のモデルとしています。

### モデルを有効にする

cms アプリケーションをインストールしたことを、プロジェクトに教えてあげる必要があります。  
`cms/apps.py` を開いてみると、CmsConfig というクラスが定義されています。
これを `mybook/settings.py` の `INSTALLED_APPS` の最後に `'cms.apps.CmsConfig',` という文字列で追加します。

```python
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'cms.apps.CmsConfig',   # cms アプリケーション
]
```

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

```bash
$ python manage.py makemigrations cms
Migrations for 'cms':
  cms/migrations/0001_initial.py
    - Create model Book
    - Create model Impression
```

このマイグレートファイルが、どのような SQL になるか、以下のコマンドで確認できます。

```bash
$ python manage.py sqlmigrate cms 0001
BEGIN;
--
-- Create model Book
--
CREATE TABLE "cms_book" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(255) NOT NULL, "publisher" varchar(255) NOT NULL, "page" integer NOT NULL);
--
-- Create model Impression
--
CREATE TABLE "cms_impression" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "comment" text NOT NULL, "book_id" integer NOT NULL REFERENCES "cms_book" ("id") DEFERRABLE INITIALLY DEFERRED);
CREATE INDEX "cms_impression_book_id_b2966102" ON "cms_impression" ("book_id");
COMMIT;
```

まだデータベースに反映していないマイグレートファイルを、以下のコマンドでデータベースに反映します。

```
$ python manage.py migrate cms

Operations to perform:
  Apply all migrations: cms
Running migrations:
  Applying cms.0001_initial... OK
```

> Django 1.7 からデータベースのマイグレートツールが標準で取り込まれたので、たとえば新しいテーブルや、既存のテーブルの項目を追加／変更したい場合、日常のルーチンワークは以下のようになります。
>
> 1. models.py を直す
> 2. $ python manage.py makemigrations app名 … models.pyの変更を拾ってマイグレートファイルを作る
> 3. $ python manage.py migrate … マイグレートファイルをデータベースに反映する


### 管理サイトの有効化

ここからは Django のいいところです。

Django には scaffold のようなアプリケーションのひな形生成、すなわち CRUD (Create、Read、Update、Delete) の自動生成はありません。
そのかわり、管理サイトというものがあって、ここからマスターメンテナンス的なデータ投入がすべてできてしまいます。

管理サイトを表示させてみましょう。

1. `python manage.py runserver` で開発用サーバを起動します。

2. `http://127.0.0.1:8000/admin/` にブラウザでアクセスします。

3. 初回の `$ python manage.py createsuperuser`　で初期化したスーパーユーザー `admin/hogefuga` でログインします。

![django02.jpg](https://qiita-image-store.s3.amazonaws.com/0/48136/5efe2970-1ff4-733b-26c8-53496b513a1d.jpeg "django02.jpg")

まだ、グループ、ユーザーしか見えていませんね。

![django03.jpg](https://qiita-image-store.s3.amazonaws.com/0/48136/ee364f5b-050b-2749-aee0-a342d304e685.jpeg "django03.jpg")


### cms モデルを admin 上で編集できるようにする

`cms/admin.py` に、管理サイトへ表示したいモデルを追加します。

```python
from django.contrib import admin
from cms.models import Book, Impression

admin.site.register(Book)
admin.site.register(Impression)
```

もう一度、`http://127.0.0.1:8000/admin/` を見てみましょう。

![django04.jpg](https://qiita-image-store.s3.amazonaws.com/0/48136/b755868a-14e8-ca55-8c6f-52ac55e119ee.jpeg "django04.jpg")


ひととおり、データの追加、修正、削除を行ってみて下さい。

![django05.jpg](https://qiita-image-store.s3.amazonaws.com/0/48136/53c0b14e-30b4-9414-6590-a5c36045b900.jpeg "django05.jpg")

![django06.jpg](https://qiita-image-store.s3.amazonaws.com/0/48136/468093c0-27ce-45b7-63b7-d65a85712045.jpeg "django06.jpg")

### 管理サイトの一覧ページをカスタマイズする

管理サイトの一覧を見た時、models.py の

```python
def __str__(self):
```

で設定したものが、レコード名として見えています。

もう少しレコードの項目全体が見えるよう、`cms/admin.py` を修正してみましょう。

> classの前は、2行開けないと、波線が出て警告されます。

```python
from django.contrib import admin

from cms.models import Book, Impression

# admin.site.register(Book)
# admin.site.register(Impression)


class BookAdmin(admin.ModelAdmin):
    list_display = ('id', 'name', 'publisher', 'page',)  # 一覧に出したい項目
    list_display_links = ('id', 'name',)  # 修正リンクでクリックできる項目


admin.site.register(Book, BookAdmin)


class ImpressionAdmin(admin.ModelAdmin):
    list_display = ('id', 'comment',)
    list_display_links = ('id', 'comment',)
    raw_id_fields = ('book',)   # 外部キーをプルダウンにしない（データ件数が増加時のタイムアウトを予防）


admin.site.register(Impression, ImpressionAdmin)

```

![django07.jpg](https://qiita-image-store.s3.amazonaws.com/0/48136/23a9b734-49b8-5c52-58fb-a5f8164bad5c.jpeg "django07.jpg")

どうでしょうか。

モデルに追加したテーブルの一覧、登録、修正、削除が簡単にできました。  
CRUDをどう作るかの説明はいらないですね？

と言ってしまうと Django の解説にならないので、自分で CRUD を作る場合の説明をしましょう。

[Python Django入門 (4)](http://qiita.com/kaki_k/items/6e17597804437ef170ae) に続きます