the dawn of yuriko hisory

アニメやら漫画関係で何か作りたいものと勉強したことのメモ用

DjangoGirlsに挑戦 ~フォームを作ろう~

フォームで作ろう

今回で最後です。頑張ります。

Djangoフォーム

フォームを作成していきます。
デフォルトではフォーム用のファイルが作成されていないので作成していきます。

app
└forms.py #追加


以下forms.py

from django import forms //1
from .models import Post

class PostForm(forms.ModelForm): //2

    class Meta: //3
        model = Post
        fields = ('title', 'text',) //4

1. Djangoに実装されてるフォームクラスをインポートします。

2.今回はモデル用のフォームを作成するためにModelsFormを利用しています。
Modelと結びつくためのフォームを作成する際は記述します。

3. class Metaはクラス内の設定を書いていく所の認識をしています。
PostFormクラス内でどういった設定をしていくのかを以下に書いていっています。

4.fieldsはmodelで指定したPostの中のどのフィールドをフォームで使用するのかを指定しています。
今回はタイトルとテキストを指定しています。

フォーム画面の表示

投稿用のページへのリンクをbase.htmlに置きます。

{% load staticfiles %}
<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title></title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" >
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/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="">the dawn of yuriko hisory</a></h1>
  </div>
  <div class="content container">
      <div class="row">
          <div class="col-md-8">
              {% block content %}
              {% endblock %}
          </div>
      </div>
  </div>
</body>
</html>

class指定については特にきにしなくて良いです。
次にURLを作成します。

from django.conf.urls import include, url
from . import views

urlpatterns = [
    url(r'^$', views.post_list),
    url(r'^post/(?P<pk>[0-9]+)/$', views.post_detail, name='post_detail'),
    url(r'^post/new/$', views.post_new, name='post_new'), //1
]

1.投稿ページのURLは一意でいいのでpost/new/へのアクセスになってます。
それ以降はいままでと特別変わりませんね。

urls.pyで指定してpost_newをViewで作ります。

from .forms import PostForm

def post_new(request):
    form = PostForm() //1
    return render(request, 'blog/post_edit.html', {'form': form})

1.ここで作成したフォームオブジェクトをテンプレートに渡してあげています。

最後にテンプレートを作成します
以下post_edit.html

{% extends 'blog/base.html' %}

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

1.formタグ
method="POST" はリクエストにPOSTメソッドを利用することを明示しています。
{% csrf_token %}は CSRF対策です。
CSRFについては別で調べる必要がありますが、
とにかくDjangoではフォーム利用時にはCSRF対策をしないとエラーが発生するので
必ず書きましょう。
ちなみにAjax処理を行う際にもCSRF対策をしないといけないみたいです。
そのうちAjaxを使った処理も行いたいです。

2.as_pは

タグでフォームを作成することを示しています。
画像のような形で出力されます。
as_ulやas_table等もありますし
細かくフォームを設定したければ普通にformから値を持ってくればいいですし
中々Djangoのフォームは便利です。
https://i.gyazo.com/d0b68d06d2d8f7fb146ce598ecb6d569.png


とりあえずこれでフォームページができました。
https://i.gyazo.com/33d9a4a9004c049c4e7b51f4776d780c.png

こんな感じになります。

POST処理

ここまでで表示はできましたが、投稿処理ができていません。
フォームを保存する処理を作成していきます。

ここで作成したViewのpost_newを修正していきます。

from django.shortcuts import redirect

def post_new(request):
    if request.method == "POST": //1
        form = PostForm(request.POST) //2
        if form.is_valid(): //3
            post = form.save(commit=False) //4
            post.author = request.user //5 
            post.save() //6
            return redirect('post_detail', pk=post.pk) //7
    else:
        form = PostForm()
    return render(request, 'blog/post_edit.html', {'form': form})

1. フォーム側でHTTPリクエストをPOSTに設定していました。
もしフォームからリクエストが送られた場合はPOSTになるので以下の処理を
初期表示時はGETが送られるのでelse以下で先ほどまでと同じ処理を行います

2. PostFormのPOSTされた値をformに渡しています。
https://i.gyazo.com/fedf63e08516fdfda5a6709f77c32d7d.png

3.is_valid()はそのままバリデーションの意味です。
ただ、バリデーションの設定はしていませんでしたね。
ですが、Postモデルで指定したものが適用されるので
未入力で送信してみるとエラーが起こります。
今回はバリデーションメッセージなどの細かい部分については触れていません。

4.form.save(commit=False)はコミットせずにPostモデルをpost変数にいれています。

5.Postモデル内のauthorにリクエストを送っているユーザーの値を設定します。
このrequest.userはどこの情報なのかがイマイチわからないです。

6.PostモデルをDBにコミットします。

7. リダイレクトで今回作ったページへと遷移します。
動き自体はわかると思います。

フォームの編集

最後に既存のものを編集するページを作成します。

個別ページ用のpost_detailに実装します。

{% extends 'blog/base.html' %}

{% block content %}
    <div class="post">
        {% if post.author %}
            <div class="date">
                {{ post.author }}
            </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|linebreaks }}</p>
    </div>
{% endblock %}

urlsの修正

from django.conf.urls import include, url
from . import views

urlpatterns = [
    url(r'^$', views.post_list),
    url(r'^post/(?P<pk>[0-9]+)/$', views.post_detail, name='post_detail'),
    url(r'^post/new/$', views.post_new, name='post_new'),
    url(r'^post/(?P<pk>[0-9]+)/edit/$', views.post_edit, name='post_edit'), #追加
]

viewの修正

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.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm(instance=post)
    return render(request, 'blog/post_edit.html', {'form': form})

フォーム作成とほぼ同じです。
今までやったことができていれば難しくありません。


以上をもってdjangogirlsは終了になります。
今後の予定については別の記事で書いていきます。