前回の続きです。

ほぼ udemy 「【3日でできる】はじめての Django 入門」の内容の備忘録になります。
今回やること
Django では、モデル(DB)にデータを格納する際、レコードごとに id が自動採番されているらしいです。(一種の主キー的なものなのかなと認識しています)
今回は、それを取り出すことと、その id を使用した処理を実現しようかと思います。
具体的には、以下をやります。
- モデルから id を取り出す
- id を使用した URL のアクセスを実現する
- 指定した id のページをジャンプするリンクを作る
モデルから id を取り出す
自動採番される id とは?
例えば以下のようなモデルを定義したとします。
class Post(models.Model):
    title = models.CharField(max_length=100)
    published = models.DateTimeField()
    image = models.ImageField(upload_to='media')
    body = models.TextField()Django にてこのモデルを使用して DB へ書き込みを行うと、整数型の id という属性も自動で定義されるという感じです。
id の取り出し
例えばこのモデルを使用してテンプレートファイル(html)で操作するとき、以下のように id を使用して処理を行うことができます。
<!--index.html-->
<!--一部省略-->
    <!--Django のテンプレート-->
    {% for post in posts.all %}
        <div style="border: 1px solid black; margin-bottom: 10px; padding: 10px;">
            #{{ post.id }} {{ post.title }}
            <br/>
            {{ post.published }}
            <br/>
            {{ post.summary }}
            <br/>
        </div>
    {% endfor %}結果としてブラウザ上では以下のように表示されます。

「#〇 タイトル名」という感じで〇のところにユニークな整数が割り当てられていることがわかります。
id を使用した URL のアクセスを実現する
よくある CRUD のパターンとして、http://xxxx/item/1 とかのように item/N (Nは整数)といった形で item の N 番目のレコードに関するページを表示するというのがあります。
つまり、レコードのインデックス指定ページです。
これを実現するために、アプリケーション(今回は posts)のファイルを以下のように変更していきます。
- ルーティングファイル(posts\urls.py)にposts/Nでアクセスできるように追記
- ビューファイル(posts\views.py)にposts/Nでアクセスした場合に表示するテンプレートファイル(html)と引数処理を追加
- テンプレートファイル(posts\templates\posts\post_detail.html)の追加
posts\urls.py に 新しい URL マッチングパターンを追加する
今回は http://127.0.0.1:8000/posts/N/ という感じで posts の後ろに id を指定できるようにします。
そのため、 posts アプリケーションのルーティング(urls.py)に以下のように追記します。
# posts\urls.py
# 一部省略
urlpatterns = [
    path('', views.index, name='index'),
    path('<int:post_id>/', views.post_detail, name='post_detail'),  # ← これ追加
]意味としては、<int:post_id>/ とすることで、「 posts/int型の数値 にマッチする URL であること」となります。
また、この URL を指定された場合は、views.py の中の post_detail 関数をコールするということを定義していると思われます。
posts\views.py にテンプレートファイルを表示する処理を追加
上記の urls.py で呼び出される post_detail 関数を追記します。
# posts\views.py
# get_object_or_404 をインポートする
from django.shortcuts import render, get_object_or_404
# 一部省略
# 以下を追記
def post_detail(request, post_id):
    # Post テーブルから post_id に合致するレコードを取り出す。なければ 404 エラーとする
    post = get_object_or_404(Post, pk=post_id)
    # post_detail.html を呼び出す。その際、引数として post を渡す
    return render(request, 'posts/post_detail.html', {'post': post})これにより、post_detail 関数を呼ばれ場合は、「テンプレートファイル post_detail.html」をコールし、引数には post テーブルの post_id インデックスのレコードを渡すということになります。
なお、get_object_or_404 関数は、「Post 内に主キー(pk)でデータをアクセスし、存在したらオブジェクトを返し、失敗したらエラーコード 404 を返す」という役割があります。
テンプレートファイル post_detail.html を追加
上記の views.py から呼び出される post_detail.html を追加します。
今回のメインは views.py で id 使って処理するところなので、このテンプレートファイルは特に目新しいことはしません。ただ単に引数で渡された Post テーブルの該当レコードを表示するだけです。
一応ソースを載せときます。
<!--post_detail.html-->
<!DOCTYPE html>
<html lang = "ja-jp">
<haed>
    <title>THIS IS TITLE</title>
</haed>
<body>
    {{ post.title }}
    <br/>
    {{ post.published }}
    <br/>
    <img src="{{ post.image.url }}"/>
    <br/>
    {{ post.body }}
    <br/>
    <br/>
</body>
</html>id を使用して URL アクセスしてみる
結果を見てみます。
以下のように、http://127.0.0.1:8000/posts/2/ というように URL に id を含めてアクセスしてみると、ちゃんとページが表示されました。

指定した id のページをジャンプするリンクを作る
最後に、リンクを作ります。
以下のような感じで、リンクを作り、このリンクをクリックすると、上記の http://127.0.0.1:8000/posts/2/ へ飛ぶ。というようなことを実現させます。

具体的な手法としては、index.html(上記の画像に該当するhttp://127.0.0.1:8000/posts/のページ)に URL ジャンプする処理を記述することになります。
テンプレートファイル index.html を修正する
以下のように index.html を修正します。
<!--index.html-->
<!--一部省略-->
    <!--Django のテンプレート-->
    {% for post in posts.all %}
        <div style="border: 1px solid black; margin-bottom: 10px; padding: 10px;">
            <a href = "{% url 'post_detail' post.id %}">{{ post.title }}</a>
            <br/>
            {{ post.published }}
            <br/>
            {{ post.summary }}
            <br/>
        </div>
    {% endfor %}ここで今まで異なるのは <a href = "{% url 'post_detail' post.id %}">{{ post.title }}</a> の部分です。
<a>タグは html でよく出てくる普通のリンクです。
しかし、 href 移行の部分が特殊です。
{% url 文字列 引数 } とすると、以下のような意味になります。
- url:URLを出力するためのコマンド
- 文字列:urlsに定義されている「name=~」の~を書く。これにバインドされている views.pyの関数をコールして、結果的にテンプレートファイルを得る
- 引数:views.pyの関数に渡す引数
これにより、今回は views.post_detail 関数をコールして、テンプレートファイル posts/post_detail.html を導出し、そのテンプレートファイルに引数として post.id を渡すことで、posts/N のアクセスを実現できます。
ちょっと今回はややこしかったですが、モデル内に自動採番される id を使っていろいろできることを学びました。
また、テンプレートファイル内で URL ジャンプする方法も学びました。
コメント