アプリケーションを拡張しよう
もうウェブサイトを作るのに必要な全ての章は終わりました。モデル、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を見て結果を確認しましょう。
うまくいってるはずです!おめでとう :)