前回の続きです。
ほぼ 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 ジャンプする方法も学びました。
コメント