Dockerで始めるDjango生活(3日目)

### 初めに
3日目です。
2日目は[こちら](https://qiita.com/ghayato/items/4c1c20e5ae28e0e06507)
前回はblogアプリを作成した所で終わっていました。
今回はモデルを実際に作成してアプリを有効化しようと思います。
### 目次
1. モデルを作成する
2. blogアプリを有効化する
3. 最後に

## 1.モデルを作成する
まずは、blogフォルダに遷移します。

```
# cd /root/projects/myproject/myproject/blog
# pwd
/root/projects/myproject/myproject/blog
# tree .
.
|-- __init__.py
|-- admin.py
|-- apps.py
|-- migrations
|   `-- __init__.py
|-- models.py
|-- tests.py
`-- views.py

1 directory, 7 files
#
```
モデルを作成するにあたって編集するのはblogディレクトリ配下のmodels.pyになります。
models.pyはデフォルトでは以下の様になっていると思います。

``` models.py(修正前)
from django.db import models

# Create your models here.
```
それでは実際にモデルを作成したいと思います。

``` models.py(修正後)
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
# Create your models here.
class Post(models.Model):
    STATUS_CHOICES = (
        ('draft', 'Draft'),
        ('published', 'Published'),
    )
    title = models.CharField(max_length=250) #データベースではVARCHARとなります。
    slug = models.SlugField(max_length=250,
                            unique_for_date='publish') #slugはURLを作成するために使用します。ここでは投稿日付を元に投稿用のURLを作成します。
    author = models.ForeignKey(User,
                              on_delete=models.CASCADE,
                              related_name='blog_posts') #外部キーでユーザーと紐づけているのでユーザーが削除されれば投稿も削除されるようにしています。
    body = models.TextField() #投稿の本文にあたります。
    publish = models.DateTimeField(default=timezone.now) #投稿の公開日時に現在時刻を指定します。
    created = models.DateTimeField(auto_now_add=True) #auto_now_addを指定すると投稿の作成時に日付が保存されます。
    updated = models.DateTimeField(auto_now=True) #auto_nowを指定すると投稿の保存時に日付が保存されます。
    status = models.CharField(max_length=10,
                              choices=STATUS_CHOICES,
                              default='draft') #投稿の状態を保存します。上でSTATUS_CHOICESは定めていてdraft(公開前),published(公開後)となり、どちらか一つの状態しか選べません。
    
    class Meta:
        ordering = ('-publish',) #メタデータを用いる事でデフォルトで結果の並び替えを行っています。この場合は-が付いているので降順になり、公開された順に投稿が表示されます。
    def __str__(self):
        return self.title #タイトルを表示します。
```

## 2. blogアプリを有効化する
Djangoがアプリを追跡して、先程作成したモデルのテーブルを作成するためには、blogアプリを有効化する必要があります。
そのためには、myprojectフォルダのsettings.pyを修正する必要があります。
まずは、ディレクトリに移動します。

```
# cd /root/projects/myproject/myproject/myproject
# pwd
/root/projects/myproject/myproject/myproject
# ls
__init__.py  __pycache__  asgi.py  settings.py  urls.py  wsgi.py
#
```
次にsettings.pyのINSTALED_APPSに追加します。

``` settings.py(修正前)
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
```
``` settings.py(修正後)
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog.apps.BlogConfig', ←追加
]
```
以上で、テーブルを作成する準備が整ったのでマイグレーションを行うとテーブルが作成されます。

```
# cd /root/projects/myproject/myproject
# pwd
/root/projects/myproject/myproject
# ls
blog  db.sqlite3  manage.py  myproject
# python3 manage.py makemigrations blog
Migrations for 'blog':
  blog/migrations/0001_initial.py
    - Create model Post
#
```
作成されるとblogディレクトリにmigrationsディレクトリが作成されその中に0001_initial.pyが作成されています。
では、先程のマイグレーションでどのようなSQLが発行されたかを見てみます。
見るためには、sqlmigrateというコマンドを使います。

```
# python3 manage.py sqlmigrate blog 0001
BEGIN;
--
-- Create model Post
--
CREATE TABLE "blog_post" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "title" varchar(250) NOT NULL, "slug" varchar(250) NOT NULL, "body" text NOT NULL, "publish" datetime NOT NULL, "created" datetime NOT NULL, "updated" datetime NOT NULL, "status" varchar(10) NOT NULL, "author_id" integer NOT NULL REFERENCES "auth_user" ("id") DEFERRABLE INITIALLY DEFERRED);
CREATE INDEX "blog_post_slug_b95473f2" ON "blog_post" ("slug");
CREATE INDEX "blog_post_author_id_dd7a8485" ON "blog_post" ("author_id");
COMMIT;
#
```
このコマンドではSQL文を実行はせずに出力します。
では、最後に今作ったblog_postをデータベースと同期させます。

```
# python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
  Applying blog.0001_initial... OK
#
```

## 3. 最後に
最後に、再度モデルを作成して有効化するまでの流れをまとめておきます。

```
models.pyに作成したい情報を書き込みます。
↓
settings.pyのINSTALLED_APPSに今回作成したいアプリを追加します。(既に追加されていた場合はこの作業は要らないです)
↓
python3 manage.py makemigrations <アプリ名>でテーブルを作成
↓
python3 manage.py migrateで同期させます。
---------以下、既存のモデルを修正した場合-----------
models.pyに修正内容を追記
↓
python3 manage.py makemigrations <アプリ名>でテーブルを作成
↓
python3 manage.py migrateで同期させます。
```
この記事では下記の本を参考に書かせていただいています。
この記事ではDjangoを実際に触って動かすことをメインに書いていますので上記のマイグレーションの詳しい説明などはこの本を読んでただければと思います。
[Django 3 By Example - Third Edition](https://www.packtpub.com/product/django-3-by-example-third-edition/9781838981952)