Django Webアプリ作成(8) フォームの作成

環境
OS : macOS Mojave
Anaconda : python3.6.7
Django==2.1.5

#ここまで
前回までで、テンプレートを拡張しページを作成するということをしました。
今回は記事を投稿できるフォームと呼ばれるものを作成したいと思います。

#フォームの作成
現在は、管理者ページ(django-admin)から入ってしか投稿できないが、サイトの表面から記事をかけるようにする。
はじめに、アプリディレクトリにforms.pyを作成する。

```:Terminal
touch blog/forms.py
```

```python:blog/forms.py
from django import forms
from .models import Post


class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ('title', 'text',)
```

編集ページ(post_edit.html)の作成

```:Terminal
touch templates/post_edit.html
```

```html:post_edit.html
{% extends 'base.html' %}

{% block content %}
    <h1>New post</h1>
    <form method="POST" class="post-form">{% csrf_token %}
        {{ form.as_p }}
        <button type="submit" class="save btn btn-default">Save</button>
    </form>
{% endblock %}
```

次にビューを作成
post_new関数を追加する

```python:blog/views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.utils import timezone
from .models import Post
from .forms import PostForm


def post_list(request):
    posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
    return render(request, 'post_list.html', {'posts': posts})


def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, 'post_detail.html', {'post': post})


def post_new(request):
    if request.method == "POST":
        form = PostForm(request.POST)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.published_date = timezone.now()
            post.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm()
    return render(request, 'blog/post_edit.html', {'form': form})
```

urls.pyにパターンを追加

```python:blog/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.post_list, name='post_list'),
    path('post/<int:pk>/', views.post_detail, name='post_detail'),
    path('post/new/', views.post_new, name='post_new'),
]
```
base.htmlの<div class="page-header">タグ内にリンクを追加する

```html:base.html
{% load staticfiles %}
<html lang="ja">
    <head>
        <title>Django blog</title>
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
        <link href="http://fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext" rel="stylesheet" type="text/css">
        <link rel="stylesheet" href="{% static 'css/blog.css' %}">
    </head>
    <body>
        <div class="page-header">
            <a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>
            <h1><a href="/">Django Girls Blog</a></h1>
        </div>
        <div class="content container">
            <div class="row">
                <div class="col-md-8">
                    {% block content %}
                    {% endblock %}
                </div>
            </div>
        </div>
    </body>
</html>
```
これで一度サーバを起動して新しい記事を投稿してみましょう。
もしエラーが出てきてしまった場合は一度、管理者ページ(/admin)でログインしてから試してみてください!
**参考** [Django Girls|フォーム](https://tutorial.djangogirls.org/ja/django_forms/)

#フォームの編集
もう少しフォームをカスタマイズしましょう。
新規投稿ページは作成したので、投稿してある記事を編集するページを作成しましょう。
post_detail.htmlを以下のように変更

```html:post_detail.html
{% extends 'base.html' %}

{% block content %}
    <div class="post">
        {% if post.published_date %}
            <div class="date">
                {{ post.published_date }}
            </div>
        {% endif %}
        <a class="btn btn-default" href="{% url 'post_edit' pk=post.pk %}"><span class="glyphicon glyphicon-pencil"></span></a>
        <h1>{{ post.title }}</h1>
        <p>{{ post.text|linebreaksbr }}</p>
    </div>
{% endblock %}
```
さらに、urls.pyに以下を追加

```python:blog/urls.py
 path('post/<int:pk>/edit/', views.post_edit, name='post_edit'),
```
さらに、views.pyに以下を追加

```python:blog/views.py
def post_edit(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == "POST":
        form = PostForm(request.POST, instance=post)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.published_date = timezone.now()
            post.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm(instance=post)
    return render(request, 'post_edit.html', {'form': form})
```

一度確認してみましょう!
ちゃんと動きましたか?