※このブログではサーバー運用、技術の検証等の費用のため広告をいれています。
記事が見づらいなどの問題がありましたらContactからお知らせください。

<前のページ
【初心者チュートリアル】Django2でブログ作成(Part11)〜uuidを使う~
次のページ>
【初心者チュートリアル】Django2でブログ作成(Part13)〜collectstatic~

【初心者チュートリアル】Django2でブログ作成(Part12)〜get_absolute_url()~

web開発 python3 Django python Djangoチュートリアル リファクタリング

投稿日:2019年11月21日

このエントリーをはてなブックマークに追加
Djangoは簡単にWebアプリケーションを作成できるフレームワークです。この記事は初心者の方向けのDjangoチュートリアルです。

はじめに

このPartでは前回Modelに追加したuuidフィールドを使ってそれぞれのURLをidを使わない定義に直していきます。また新しくget_absolute_url()というメソッドも定義して使っていきます。


識別子をidからuuidに変更

まずはviews.pyarticle_detail()メソッドを改修しましょう。

sample_blog/blog/views.py
[...]

def article_detail(request, uuid):    # 受け取る引数名をわかりやすくuuidに変更
    """
    記事の詳細を表示する
    """
    article = get_object_or_404(Article, uuid=uuid)    # 識別子をuuidにする

    return render(
        request,
        "blog/article_detail.html",
        {"article":article}
    )

[...]

次にurls.pyarticle_detailのURLのパターンを書き換えましょう。

sample_blog/blog/urls.py
from django.urls import path, re_path
from . import views

app_name = 'blog'

urlpatterns = [
    # post views
    path('', views.article_list, name='article_list'),
    path('<uuid:uuid>/',      # uuidをパースできる様に修正
         views.article_detail,
         name='article_detail'),
]

<int:id>の部分を<uuid:uuid>に変更しました。
※ちなみにDjango1.11までは正規表現で(?P<uuid>[0-9a-f-]+)の様に書かないと行けなかったんです。(便利になった!!)
次にtemplateの参照urlをuuidに変更しましょう。ここもiduuidに変更するだけでOKです。

sample_blog/templates/blog/article_list.html
{% extends "base.html" %}
{% block title %}ブログ一覧|Sampleブログ{% endblock %}
{% block content %}
  <h1>ブログ一覧</h1>
  {% for article in articles %}
    <h2>
      <a href="{% url 'blog:article_detail' uuid=article.uuid %}">
        {{ article.title }}
      </a>
    </h2>
    <p class="date">
      公開日:{{ article.publish }}
    </p>
    <p>by {{ article.author }}</p>
    {{ article.body|truncatewords:30 }}
  {% endfor %}
{% endblock %}

これでOKです。開発用サーバーを起動してhttp://localhost:8000/blog/にアクセスして動作を確認してみましょう。

ターミナル
$ python manage.py runserver
▲問題なく動いている

urlの識別子もuuidになったことで、それぞれの記事のURLが予測できなくなっていますね。

▲記事のURL

記事も問題なく見れるようになったことだし、冒頭に話したget_absolute_url()を実装して使ってみましょう。


get_absolute_url

get_absolute_url()とは?

DjangoではModelにはそのModelの詳細ページのURLを返すget_absolute_url()というメソッドを定義することが推奨されています。
なぜわざわざこのようなメソッドを定義するのか理由は後述するとして、まずは実装してみましょう。

Articleクラスに実装してみよう

sample_blog/blog/models.py
[...]
from django.urls import reverse
[...]

class Article(models.Model):
    [....]
    def get_absolute_url(self):
        return reverse("blog:article_detail", args=[self.uuid])

今現状ではブログ記事一覧からブログ記事詳細のページに飛ぶ時のリンクはDjangoの{% url %}タグを使っていますね。Articleクラスに実装したget_absolute_url()を使って置き換えてみましょう。

sample_blog/templates/blog/article_list.html
{% extends "base.html" %}
{% block title %}ブログ一覧|Sampleブログ{% endblock %}
{% block content %}
  <h1>ブログ一覧</h1>
  {% for article in articles %}
    <h2>
      <a href="{{ article.get_absolute_url }}">
        {{ article.title }}
      </a>
    </h2>
    <p class="date">
      公開日:{{ article.publish }}
    </p>
    <p>by {{ article.author }}</p>
    {{ article.body|truncatewords:30 }}
  {% endfor %}
{% endblock %}

この様にget_absolute_url()はよくDjangoテンプレートに記述されます。Webサイトではレコード一覧にそのレコードの詳細へのリンクをつけるということを良くするのです。(ex.友達リストからその友達のHomeページ、商品リストからその商品の詳細ページ...)そのような場合にはこのメソッドを使うと良いでしょう。

管理サイトでのget_absolute_url()

get_absolute_url()はDjangoの管理サイトでもデフォルトで使われる様になっています。開発用サーバーを起動して管理サイトArticleをみてみましょう。

ターミナル
$ python manage.py runserver

対象のモデルクラスにget_absolute_url()が実装してあると管理サイトから『VIEW ON SITE』で直接そのレコードの詳細ページに飛ぶことができます。

▲直接ページを見に行く

ブログサイトを運営していくことを考えると、管理サイトで記事を編集して、『VIEW ON SITE』から描画を確認して、気になるところがあればすぐ戻って編集...
の様になかなか便利に使えそうですね。

なぜこのメソッドを使う?

get_absolute_url()を使う理由は簡単に3つあります。

  1. URLパラメータの変更に強い
  2. HTMLをより簡素にできる
  3. 同じtemplateを使いまわせる

それぞれ解説します。

1.URLパラメータの変更に強い

今回のPartではview関数がurlから受け取るパラメータをidからuuidに変更しました。実際にwebサイトを作っていく際にはこのような変更は何度も体験するでしょう。その時{% url %}タグでurlを定義していると、そのurlを毎回変更しなくてはいけません。
実際には同じurlの定義を同一ページ内で何度も使ったりする(最新記事一覧とか、関連記事一覧とか同じページにあるよね?)ため、変更のたびに大きな労力を使う事になるでしょう。
その点HTMLのurlもget_absolute_urlを使っておけば、urls.pyとmodelのget_absolute_url()関数の内部の処理の変更だけすればOKです。

2.HTMLをより簡素にできる

HTMLはただでさえ複雑になりがちです。特にDjangoのテンプレート言語を使っていると余計ややこしくなるでしょう。Python側でまとめられる処理はそちらに書いてしまえるほうが確かに良さそうですね

3.同じtemplateを使いまわせる

例えば以下の様なtemplateがあったとしましょう。

sample.html
<div>
{% for data in data_list %}
<a href="{{ data.get_absolute_url }}">data.name</a>
{% endfor %}
</div>

この時このテンプレートはフィールドにnameさえ持ってるどのModelでも使える事になります。もし{% url %}タグで書いてしまった場合URLの名前の参照と、パラメータの渡しがHTML上に書かれる事になるため、使い回しができないというわけです。

もちろんこのget_absolute_url()だけでなく、Djangoテンプレート上で同じ様な処理が複数回出てきた場合には、その処理をModel側で新たなメソッドとして管理できないか考えてみると、templateの管理が楽になってくるかも...?


さいごに

まとめ

  • Modelの詳細ページがある場合にはget_absolute_url()を使うことを考えよう。

参考書籍

このエントリーをはてなブックマークに追加

<前のページ
【初心者チュートリアル】Django2でブログ作成(Part11)〜uuidを使う~
次のページ>
【初心者チュートリアル】Django2でブログ作成(Part13)〜collectstatic~

関連記事

記事へのコメント