アプリケーションを拡張しよう
もうウェブサイトを作るのに必要な全ての章は終わりました。モデル、URL、ビュー、テンプレートの書き方はわかっていますし、またウェブサイトを素敵にするやり方もわかります。
さあ練習しましょう!
ブログに最初に必要なものはおそらく、記事を表示するページですよね。
もうPostモデルが入っていますから、models.pyは追加する必要はありません
投稿の詳細へのテンプレートリンクを作成する
blog/templates/blog/post_list.htmlファイルにリンクを追加していきましょう。 コードエディタで開いたら、次のようになっていますよね:
blog/templates/blog/post_list.html
{% extends 'blog/base.html' %}
{% block content %}
{% for post in posts %}
<div class="post">
<div class="date">
{{ post.published_date }}
</div>
<h2><a href="">{{ post.title }}</a></h2>
<p>{{ post.text|linebreaksbr }}</p>
</div>
{% endfor %}
{% endblock %}
投稿リストの投稿のタイトルから投稿の詳細ページへのリンクを作りたいです。 投稿の詳細ページにリンクするように<h2><a href="">{{ post.title }}</a></h2>を変更しましょう。
blog/templates/blog/post_list.html
<h2><a href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a></h2>
不思議な{% url 'post_detail' pk = post.pk %}を説明します。 気づいたかもしれませんが、{% %}という表記はDjangoのテンプレートタグを使用していることを意味しています。 今私たちはこれをURLを作るために使います!
post_detailの部分は、Djangoがblog/urls.pyに書かれた name=post_detail のURLを待ち受けることを表しています。
そしてpk=post.pkについてはどうでしょうか? pkはプライマリキーの略で、データベースの各レコードのユニークな名前です。 Postモデルでプライマリキーを指定しなかったので、Djangoは私たちのために1つのキーを作成し(デフォルトでは、各レコードごとに1ずつ増える数字で、たとえば1、2、3です)、各投稿にpkというフィールド名で追加します。 Postオブジェクトの他のフィールド(title、authorなど)にアクセスするのと同じ方法で、post.pkと書くことによってプライマリキーにアクセスします!
さて、私たちが http://127.0.0.1:8000/ に行くとエラーが出ます(知っての通り、URLもpost_detailのビューもまだ作っていないので)。 このようになります:

投稿の詳細へのURLを作成する
post_detail ビュー用にurls.pyにURLを作成しましょう!
最初の投稿の詳細がこのURLで表示されるようにします:http://127.0.0.1:8000/post/1/
投稿の内容を表示するpost_detailというビューをDjangoに示すように、blog/urls.pyファイルでURLを作りましょう。 blog/urls.pyをエディタで開いて、path('post/<int:pk>/', views.post_detail, name='post_detail'),という行を追加しましょう。ファイルは次のようになるでしょう。
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'),
]
post/<int:pk>/ の部分はURLパターンを指定しています。それについて説明しましょう:
post/はURLが post に続けて / で始まることを意味します。ここまでは順調ですね。<int:pk>– この部分はトリッキーです。これはDjangoは整数の値を期待し、その値がpkという名前の変数でビューに渡されることを意味しています。/– それからURLの最後に再び / が必要です。
つまり、ブラウザにhttp://127.0.0.1:8000/post/5/を入力すると、Djangoはpost_detailというビューを探していると理解します。そしてpkが5という情報をそのビューに転送します。
よし、私たちは blog/urls.py に新しい URL パターンを追加しました! ページを更新しましょう:http://127.0.0.1:8000/ ドーン! サーバーが再び実行を停止しました。 コンソールを見てください - 予想通り、もう一つのエラーがあります!

あなたは次のステップが何であるか覚えていますか? ビューを追加する!ですね。
投稿の詳細ビューを追加する
今回はビューに追加のパラメータpkが与えられます。 私たちのビューはそれを受け取る必要がありますね? そこで関数をdef post_detail(request, pk):として定義します。 urlsで指定した名前(pk)とまったく同じ名前を使用する必要があることに注意してください。 この変数を省略するのは正しくないのでエラーになってしまいます!
今、私たちは1つだけブログ投稿を取得したいと考えています。 これを行うには、次のようなクエリセットが使用できます。
blog/views.py
Post.objects.get(pk=pk)
しかし、このコードには問題があります。 与えられたプライマリキー(pk)を持つPostが存在しない場合、とてもダサいエラーが発生します。

私たちはそれを望んでいません! しかし幸運にもDjangoにはそれを処理するものがあります:get_object_or_404 です。 与えられたpkのPostがない場合、前よりもっとよい Page Not Found 404 ページが表示されます。

いい知らせとして実際には自分のPage not foundページを作って自分の好きなようにきれいにすることができます。しかしそれは今すごく重要ではないので、私たちはそれをスキップします。
よし、今こそビューをviews.pyファイルに追加するときです!
blog/urls.pyではviews.post_detailというビューを参照するpost_detailという名前のURLルールを作成しました。 これは、Djangoがblog/views.py内のpost_detailというビュー関数を待っていることを意味します。
blog/views.pyをコードエディタで開き、他のfrom行の近くに次のコードを追加する必要があります。
blog/views.py
from django.shortcuts import render, get_object_or_404
ファイルの最後にビューを追加します:
blog/views.py
def post_detail(request, pk):
post = get_object_or_404(Post, pk=pk)
return render(request, 'blog/post_detail.html', {'post': post})
ページを更新してみましょう:http://127.0.0.1:8000/

出来ましたね! しかし、ブログ投稿のタイトルのリンクをクリックするとどうなりますか?

あらいやだ! 別のエラー! しかし、私たちはすでにそれに対処する方法をすでに知っていますね。 そう!テンプレートを追加する必要があります!
投稿の詳細へのテンプレートリンクを作成する
blog/templates/blogにpost_detail.htmlというファイルを作成し、コードエディタで開きます。
こんな感じですね。
blog/templates/blog/post_detail.html
{% extends 'blog/base.html' %}
{% block content %}
<div class="post">
{% if post.published_date %}
<div class="date">
{{ post.published_date }}
</div>
{% endif %}
<h2>{{ post.title }}</h2>
<p>{{ post.text|linebreaksbr }}</p>
</div>
{% endblock %}
もう一度base.htmlを拡張します。 contentブロックでは、投稿の公開日(存在する場合)、タイトル、およびテキストを表示します。 ここで重要なポイントについて見てみます。
{% if ... %} ... {%endif%}は、何かをチェックしたいときに使用できるテンプレートタグです。 (if ... else...をPython入門のチャプターでやったのを覚えていますか?) この場合、投稿のpublished_date(公開日)が空でないかを確認します。
これで、ページを更新してTemplateDoesNotExistがもうなくなったかどうか確認できます。

イェーイ!うまくできていますね!
デプロイの時間です!
あなたのウェブサイトがまだPythonAnywhere上で動くとしたらいいでしょう?またデプロイしてみましょう。
command-line
$ git status
$ git add --all .
$ git status
$ git commit -m "Added view and template for detailed blog post as well as CSS for the site."
$ git push
それから、PythonAnywhere Bash コンソールで:
PythonAnywhere command-line
$ cd ~/<your-pythonanywhere-domain>.pythonanywhere.com
$ git pull
[...]
(<your-pythonanywhere-domain>の部分を、自分の実際のPythonAnywhereのサブドメイン名に山カッコをはずして置き換えることを忘れずに。)
サーバー上の静的ファイルの更新
PythonAnywhereのようなサーバは、(CSSファイルのような)「静的ファイル」をPythonファイルとは違って扱うのが好きです。なぜなら、それらが高速に読み込まれるように最適化できるからです。 その結果、CSSファイルを変更するたびに、サーバー上で追加のコマンドを実行して、更新するように指示する必要があります。 コマンドはcollectstaticです。
もし仮想環境(virtualenv)が有効になっていなければ有効化するところから始めましょう (PythonAnywhereではこれを行うためにworkonというコマンドを使用します。これはあなたが自身のコンピュータで使用しているsource myenv/bin/activateコマンドと同じようなものです) 。
PythonAnywhere command-line
$ workon <your-pythonanywhere-domain>.pythonanywhere.com
(ola.pythonanywhere.com)$ python manage.py collectstatic
[...]
manage.py collectstaticコマンドは、manage.py migrateのようなものです。 私たちはコードをいくつか変更してから、Djangoにサーバの静的ファイルのコレクションまたはデータベースに変更を適用するよう指示します。
いずれにしても、「Web」ページを(コンソールの右上のメニューボタンから)開き、Reloadをクリックする準備ができました。そうしたらhttps://subdomain.pythonanywhere.comを見て結果を確認しましょう。
うまくいってるはずです!おめでとう :)