Django2 入門チュートリアル – CRUDの基本を簡単なサンプルで学ぶ – 4 – 汎用クラスベースビューによるCRUDの実装

このチュートリアルはDjango2 入門チュートリアル – CRUDの基本を簡単なサンプルで学ぶ – 3 – Django Adminの続きです。

汎用クラスベースビュー(※1)を使ってCRUDを実装していきます。Django 2 の標準搭載機能をフル活用し、ブログ・アプリを効率的に実装していきましょう。

※1「汎用クラスベースビュー」を「クラスベース汎用ビュー」と呼ぶこともありますが、このコラムではDjango2.0の公式ドキュメントに準じて「汎用クラスベースビュー」で統一します。
https://docs.djangoproject.com/ja/2.0/ref/class-based-views/generic-display/

ここまでの振り返り

状況整理のため第1回から第3回までを簡単に振り返ってみましょう。

これらを実施してきた結果、ディテクトリ・ファイル構造は下記の状態になっているかと思います。

ソースコードとデモサイト

下記よりこのチュートリアルの最終ソースコードとデモサイトをチェックできます。デモサイトを先にチェックすると、記事内容がわかりやすいかと思います。

ソースコード
https://github.com/toksan/django2_tutorial_blog

デモサイト
https://tutorialblog.it-engineer-lab.com

 

ブログ・アプリの要件

作成するブログ・アプリの要件を確認しましょう。下記の5機能(5画面)です。

  • 記事一覧の表示
  • 記事詳細の表示(1投稿の表示)
  • 記事の新規追加
  • 記事の内容変更
  • 記事の削除

このチュートリアルの目的はDjango2によるCRUDの学習のためログイン機能(認証)については省略しています。Djangoの認証機能については別の機会で紹介できればと思います。

 

Django のワークフロー

Djangoによるアプリ開発は公式チュートリアルのワークフローのように

  1. モデル作成とマイグレーション(models.py, migration)
  2. URL設計・ルーティング(urls.py)
  3. ビューの作成(views.py)
  4. テンプレートの作成(templates)
  5. 静的ファイルの作成と設置(static files)

の順で進めるとスムーズです。このチュートリアルでもこのワークフローに沿って進めていきます。

実際の実装は1機能・画面ずつ試行錯誤しながら行いましたが、工程を行ったり来たりしながら説明すると、はじめての方の混乱を招いてしまいます。そのため以下では複数の機能・画面をまとめる形で簡潔に説明しています。

 

1. モデルの作成とマイグレーション

こちらは第2回で実装済みのため、この記事では省略します。Django2 入門チュートリアル – CRUDの基本を簡単なサンプルで学ぶ – 2 – モデルとマイグレーションを参照ください。

ただし後ほど (エラー対策のため)Post モデルに1点だけ修正を加えます。

 

2. URL設定・ルーティング(URLConf)

Djangoのルーティングは「アプリレベルのURL設定」と「プロジェクトレベルのURL設定」の2つを行う必要があります。

Ruby on Rails、Laravel、CakePHP といった他言語の人気フレームワークと比較すると、Django のルーティングは少し煩雑ですが、どのFWも一長一短があるものです。

アプリレベルのURL設定

まずはアプリレベルのURL設定のため myblog/blogs/urls.py を新規作成します。

※Django2.0 のアプリ作成コマンド  $ python manage.py startapp blogs  はアプリレベルの urls.py を自動生成しないので、新規作成する必要があります。

 

はじめての Django アプリ作成、その 3 と はじめての Django アプリ作成、その 4 で学んだ Django の基本中の基本ですね。

各ルーティングには views.IndexViews.as_view() とか  views.CreateView.as_view()  といった記述がありますが、これらは次の工程「3. ビューの作成(views.py)」で定義するビュークラスのメソッドです。後ほど説明します。

プロジェクトレベルのURL設定

アプリレベルのURL設定をプロジェクトレベルのURL設定に追加しましょう。myblog/myblog/urls.py を下記のように変更すれば追加完了です。忘れてしまっている場合は はじめての Django アプリ作成、その 1 を復習しましょう。

 

 

3. ビューの作成(views.py)

続いてアプリレベルのURL設定に対応するビューを作成しましょう。

Django の「ビュー」は Ruby on Rails、Laravel、CakePHP といった他言語の人気MVCフレームワークでいう「コントローラ」に(おおよそ)相当します。Django の「テンプレート」は他MVCフレームワークの「ビュー」に相当します。用語の違いに注意しましょう。

典型的なCRUD処理は、汎用クラスベースビュー・クラスを継承することで、驚くほど少ないコードで実装できてしまいます。

 

改行を含めてわずか35行程です!

35行程度で新規追加、変更、削除はもちろん、ページネーション(IndexView)まで対応しています。

GETやPOSTされるリクエストデータとPostモデルを使って事細かに処理することもできますが、汎用クラスベースビューをうまく利用すれば、開発効率を飛躍的に高めることができます。

ここで使用した汎用クラスベースビューの詳細はGeneric display ビュー Generic editing ビュー でチェックできます。

Tip

ここでは template_name によりテンプレートファイルを明示的に指定しましたが、自動捜査されるテンプレートファイル(アプリ名/モデル名_list.htmlなど)に合わせこめば省略することも可能です。

https://docs.djangoproject.com/ja/2.0/topics/class-based-views/generic-display/#generic-views-of-objects

 

4. テンプレートの作成(templates)

テンプレートに関する規約

フレームワークの多くはテンプレートについてのディレクトリ構成やファイル名の規約がありますが、Django にはガチガチの規約はなく、比較的自由に配置できてしまいます。

実際 $ python manage.py startproject xxxx や $ python manage.py startapp xxxx といった雛形生成コマンドを実行しても、テンプレートに関するディレクトリやファイルは自動生成されません。

templates というディレクトリをプロジェクト・ルート直下に作成するも良し、各アプリケーション直下に作成するも良しです。

自由度が高いといえば聞こえは良いですが、プロジェクトで方針を定めないとカオスになるので注意しましょう。

ここではDjango公式チュートリアルと同様ように、すべてのテンプレートファイルをアプリケーション直下に設置することにします。

テンプレートの作成

myblog/blogs/templates/blogs/ というディレクトリを作成して、ビューに対応する形でファイルを作成します。

 

なぜ blogs/templates/blogs/ のようなディレクトリ階層にするのか?最後の blogsディレクトリが不要に思うかもしれませんが、ミスではありません。最後の blogs ディレクトリは「テンプレートの名前空間」という意味を持ちます。

テンプレートの名前空間

作ったテンプレートを polls という別のサブディレクトリを作らずに、直接 polls/templates の中に置いてもいいのではないか、と思うかもしれませんね。しかし、それは実際には悪い考えです。Django は、名前がマッチした最初のテンプレートを使用するので、もし 異なる アプリケーションの中に同じ名前のテンプレートがあった場合、Django はそれらを区別することができません。そのため、Django に正しいテンプレートを教えてあげる必要がありますが、一番簡単な方法は、それらに 名前空間を与える ことです。アプリケーションと同じ名前をつけた もう一つの ディレクトリの中にテンプレートを置いたのは、そういうわけなのです。

https://docs.djangoproject.com/ja/2.0/intro/tutorial03/  より引用

テンプレートファイルについての補足説明

ソースコードはGitHubにて

各ファイルのソースコードをこの場で書くと煩雑なので、GitHubを参照しながら読み進めてください。
GitHubでテンプレートのソースコードを見る

レイアウトファイル

base.html はいわゆるレイアウト・ファイルです。ヘッダ・フッタ等の共通パーツを切り出しておきます。ファイル名の規約はありませんが、Djangoではレイアウトファイル名を base.html とすることが多いようです。

index.html や create.html といった他のテンプレートファイルは、この base.html を {% extends ‘blogs/base.html’ %} によって取り込みます。

汎用クラスベースビューとテンプレート変数

各テンプレートファイルで唐突に object, object_list, form といった変数が出現していますが、これらは汎用クラスビューが自動的に埋め込むテンプレート変数です。
参考: Generic display ビューGeneric editing ビュー

CSRF対策

サイト内部URLに対してPOSTするフォームには必ず {% csrf_token %} をつけましょう。これはCSRF(クロスサイトリクエストフォージェリ)という攻撃に対するセキュリティ対策です。

なお、外部URLにPOSTする場合には {% csrf_token %}  をつけてはいけません。CSRF トークンが外部に漏れ、脆弱性の原因となります。

CSRF については、 Django 2 公式ドキュメントのクロスサイトリクエストフォージェリ (CSRF) 対策を参照下さい。

 

Post モデルの修正

以上でベースとなるシステムは完成、CSSでデザイン調整をするだけ!と言いたいところですが、create や update の処理時に1点不具合があります。

開発サーバを立ち上げて http://127.0.0.1:8000/create/  にアクセスしてみましょう。

ブログ記事の新規作成画面

 

新規作成画面のSaveボタンを押して送信すると、下のようなエラー画面になります。

No URL to redirect to. Either provide a url or define a get_absolute_url method on the Model

No URL to redirect to. Either provide a url or define a get_absolute_url method on the Model.

(データ保存処理後に)リダイレクトするURLが指定されてません。URLを指定するか get_absolute_url というメソッドをモデルに定義しなさい、とのことです。

このエラーの対処方法は(おもに)2パターンあります。

どちらの方法でも良いですが、今回は define a get_absolute_url method on the Model. すなわちPostモデルにget_absolute_url というメソッドを実装する方法を採用します。

myblog/blogs/model.py  に get_absolute_url というインスタンスメソッドを定義し、URL文字列またはDjangoのreverse()関数を通したURLを返します。ここでは単純に記事一覧ページにリダイレクトするよう設定してみました。

※モデルファイルの全ソースはGitHubを参照ください。

ちなみにもう1つの方法では myblog/blogs/views.py を編集します。DeleteViewクラスと同じように IndexView, UpdateView クラスの中に success_url プロパティを追加して、URLを指定しましょう。※def get_success_url(self) を定義してもOK

 

その他、stackoverflow に汎用ビューの引数として指定する方法も載っています。(試してませんが)myblog/blogs/urls.py で指定すれば多分うまくいくでしょう。

 

5. 静的ファイルの作成と設置(static files)

CSS、JavaScript 、画像(PNG/JPEG/GIF etc.)等の静的ファイルについては、公式チュートリアルはじめての Django アプリ作成、その 6 の内容を忠実に実践するだけです。あわせてDjango公式ドキュメント 静的ファイル (画像、JavaScript、CSS など) の管理静的ファイルのデプロイ に目を通しておけば静的ファイルについては十分でしょう。

静的ファイルの設定

プロジェクト設定に myblog/myblog/settings.py の最下部に静的ファイルの設定を追加します。

 

スタイルシートの追加

myblog/blogs/static/blogs/css/ というディレクトリを作成して、style.css を作成します。

 

テンプレート・ファイル同様に blogs という階層は不要に感じますが、「静的ファイルの名前空間」という意味があります。

静的ファイルの名前空間

テンプレートと同様に、polls という別のサブディレクトリを作らずに、直接 polls/static の中に静的ファイルを置いてもいいのではないか、と思うかもしれませんね。しかし、それは実際には悪い考えです。Django は、名前がマッチした最初のテンプレートを使用するので、もし 異なる アプリケーションの中に同じ名前のテンプレートがあった場合、Django はそれらを区別することができません。そのため、Django に正しいテンプレートを教えてあげる必要がありますが、一番簡単な方法は、それらに 名前空間を与える ことです。アプリケーションと同じ名前をつけた もう一つの ディレクトリの中にテンプレートを置いたのは、そういうわけなのです。

https://docs.djangoproject.com/ja/2.0/intro/tutorial06/ より引用

 

style.css はスタイル調整をしているだけの極ふつうのCSSファイルです。テキトーに殴り書きしたCSSですが、見たい方は GitHub を参照ください。

このチュートリアルに必要な静的ファイルはCSSファイルだけです。JavaScript や画像は設定しませんが、実装方法はまったく同じです。

 

以上で完了です。

書くのもとても大変でしたが、読むのも大変だったと思います。お疲れ様でした!

このチュートリアルのソースコードとデモサイトは下記より参照可能です。

 

ソースコード
https://github.com/toksan/django2_tutorial_blog

 

デモサイト
https://tutorialblog.it-engineer-lab.com

この記事が役に立ったら是非シェアください!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です