Djangoで簡単な投稿フォームを作成する

#概要
Djangoの`TemplateView`で「ユーザーが投稿できるフォーム画面」を実装したいと思います。

今回は、タイトルとメモを投稿するフォームになっています。（掲示板みたいな）

なお、環境は`python 3.7.3`、`django 2.2`になります。

#1. プロジェクト作成
1-1. まずはプロジェクトファイルを作りたいので、下記のコマンドでディレクトリを作成します。

```:terminal
$ mkdir simpleform
```

1-2. 次に`simpleform`というプロジェクトを作成します。最後の`.`は正しいので、そのとおり実行してください。（ディレクトリは`simpleform`であることを確認してください）

```:terminal
~simpleform$ django-admin startproject formproject .
```

1-3. コマンドを実行すると`simpleform`ディレクトリには、下記のようにファイルが生成されます。

```:simpleform/
simpleform
├── formproject
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py
```

#2. アプリケーションを作成
2-1. 新しくアプリケーションを作成したいので、下記のコマンドを実行します。今回は、`formapp`というアプリケーションです。

```:terminal
$ python manage.py startapp formapp
```

実行したらディレクトリは下記のようになると思います。

ざっくり３つに分けると、`simpleform`というプロジェクトファイル内に、①`formapp`というアプリケーション、②`formproject`というプロジェクト、③`manage.py`ファイルになります。

```:simpleform/
simpleform
├── formapp
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── formproject
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-37.pyc
│   │   └── settings.cpython-37.pyc
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py
```

2-2. `formproject`の`settings.py`にある`INSTALLED_APPS`に、`formapp`を追加します。

```python:formproject/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    #追加
    'formapp',
]
```

2-3. `form`と投稿一覧の`list`を表示できるよう`TEMPLATES`にも設定をします。`DIRS`に`[BASE_DIR, 'templates'`を追加します。

```python:formproject/settings.py
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        #追加
        'DIRS': [BASE_DIR, 'templates'],
        #ここまで
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
```

#3. Formを表示させよう
3-1. まずは、`formproject/urls.py`に下記のように追加してください。

```python:formproject/urls.py
from django.contrib import admin
#includeを追加
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    #追加
    path('', include('formapp.urls')),
]
```

3-2. `formapp`に`urls.py`ファイルを新規作成して、下記のコードを追加してください。これで、`https://サイト名.com/form`とアクセスすれば、`form`が表示され、`https://サイト名.com/list`とアクセスすれば、投稿一覧の`list`が表示されます。

```python:formapp/urls.py
from django.urls import path
from .views import FormClass, ListClass

urlpatterns = [
    path('form/', FormClass.as_view(), name='form'),
    path('list/', ListClass.as_view(), name='list'),
]
```

3-3. 後ほど作成する`form.html`と`list.html`ファイルにアクセスできるよう、`views.py`にコードを追加してください。

```python:formapp/views.py
from django.views.generic import ListView, CreateView
from django.urls import reverse_lazy
from .models import PostModel

class ListClass(ListView):
    template_name = 'list.html'
    model = PostModel

class FormClass(CreateView):
    template_name = 'form.html'
    model = PostModel
    fields = ('title','memo')
    success_url = reverse_lazy('list')
```

3-4. `views.py`に継承するモデルの`models.py`は、下記のように作成してください。

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

class PostModel(models.Model):
    title = models.CharField(max_length=50)
    memo = models.TextField()
```

3-5. `templates`フォルダーを`simpleform`に新規作成してください。その中に`form.html`と`list.html`を新規作成し、下記のようにしてください。

```html:simpleform/templates/form.html
<form method="POST">
{% csrf_token %}
  <p>タイトル：<input type="text" name="title"></p>
  <p>メモ：<input type="text" name="memo"></p>
  <input type="submit" value="投稿する">
</form>
```

```html:simpleform/templates/list.html
<div class="container">
  {% for post in object_list %}
  <div class="post">
    <p>タイトル：{{ post.title }}</p>
    <p>メモ：{{ post.memo }}</p>
    <p>--------------------</p>
  </div>
  {% endfor %}
  <div class="form">
    <a href="{% url 'form' %}">新規投稿</a>
  </div>
</div>
```

ディレクトリは下記のようになるはずです。

```:simpleform/
simpleform
├── formapp
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── formproject
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-37.pyc
│   │   └── settings.cpython-37.pyc
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py
└── templates
    ├── form.html
    └── list.html
```

3-6. 最後に下記のコマンドを実行してください。

```:terminal
$ python manage.py migrate
```

#4. localhost起動
4-1. localhostを起動して、`form`と`list`が表示されるか確認したいので、`runserver`を実行します。

```:terminal
$ python manage.py runserver
```

4-2. [http://localhost:8000/form](http://localhost:8000/form)をブラウザーで開くと、このようなフォームが表示されるはずです。
![form1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403981/c5e63507-af0d-f7b2-b709-bb11c7a9eb29.png)

①試しに書き込みをして、「投稿する」を押してみてください。
![form2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403981/e51fb3c9-0747-2cb1-352a-403e00dc309a.png)

②そうしたら、投稿一覧が表示されます。
![form3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403981/8d15c760-248b-3c0d-dc71-b69e59745bf5.png)

③最後に「新規投稿」を押して、同じように投稿してみると...
![form4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403981/2c886956-e4b5-28cb-4e8b-0a038afac686.png)

...しっかり投稿できています！

このように投稿画面と一覧表示が動作していれば、正しく実行できています。

以上