Django で自動採番された id を使用する

Python

前回の続きです。

Django で画像を表示する
前回の続きです。ほぼ udemy 「【3日でできる】はじめての Django 入門」の内容の備忘録になります。今回やることブラウザに画像を表示します。が、正直今回のはややこしいというか、わけがわかっていないです・・・仕様的なもの...

ほぼ udemy 「【3日でできる】はじめての Django 入門」の内容の備忘録になります。

今回やること

Django では、モデル(DB)にデータを格納する際、レコードごとに id が自動採番されているらしいです。(一種の主キー的なものなのかなと認識しています)
今回は、それを取り出すことと、その id を使用した処理を実現しようかと思います。

具体的には、以下をやります。

  1. モデルから id を取り出す
  2. id を使用した URL のアクセスを実現する
  3. 指定した 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)のファイルを以下のように変更していきます。

  1. ルーティングファイル(posts\urls.py)に posts/N でアクセスできるように追記
  2. ビューファイル(posts\views.py)に posts/N でアクセスした場合に表示するテンプレートファイル(html)と引数処理を追加
  3. テンプレートファイル(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 ジャンプする方法も学びました。

コメント

タイトルとURLをコピーしました