【Django】ブログのURLの末尾を文字列に変える方法

ブラウザのURLの部分の画像

今日はURLの末尾を数字から文字列に変える方法をやっていくよ
URLを読めばどんな記事なのかなんとなくわかるようになるね!

あたなのブログ記事のURLの末尾はどのようになっていますか?

1、2のような数字になっている人もいるかもしれませんが、これを文字列にもすることができます。

URLの末尾が文字列になっている画像

記事の内容を表す文字列にすることでURLに意味を与えることで少しだけサイトの格を上げることができます。

本記事の対象者
  • Djangoでブログを作成している人
目次目次[閉じる]

モデルにslugを加える

まずはブログのModels.pyの中で定義したクラスに「slug(スラグ)」の項目を追加します。

class Blog(models.Model):
    category = models.ForeignKey(Category, on_delete=models.PROTECT)
    title = models.CharField(blank=False, null=False, max_length=150)
    keywords = models.CharField(blank=True, max_length=150)
    slug = models.SlugField(blank=False,unique=True)  #ここを追加
    text = MDTextField(blank=True)
    create_datetime = models.DateTimeField(auto_now_add=True)
    publish_time = models.DateTimeField(blank=True, null=True)
    is_public = models.BooleanField(default=False)

URLは重複してはいけないので、blank=Falseunique=Trueは必ず入れる必要がありますが、1点注意です。

すでに定義したモデルに対してデータが存在している場合はpython manage.py makemigrationsでマイグレーションしようとすると、以下のような表示が出てきます。

You are trying to add a non-nullable field 'slug' to post without a default; we can't do that (the database needs something to populate existing rows). Please select a fix: 1) Provide a one-off default now (will be set on all existing rows with a null value for this column) 2) Quit, and let me add a default in models.py

これは空白が許されない(blank=False)フィールドを作ったのにデフォルト値を設定していないので実行できません、と言われています。

そのあとに書かれているのは①何か同じ値をデフォルトして入れる②マイグレーションを止める、という選択肢ですが、②を選びましょう。

①を選択して統一のデフォルト値を入れるとその値がユニークではないということでuniaue=Trueに抵触してエラーになります。

テクニック的にはまずはblank=Trueunique=Falseとして空白も重複もありにしましょう。

その上で一度マイグレーションして管理画面でslugにユニークな値を設定してからblank=Falseunique=Trueに修正します。

admin画面のslugの入力部分

これでモデルの準備は完了です。

アプリケーションのurls.pyを変更する

次にアプリケーションのurls.pyの設定をします。

app_name = 'blogs'
urlpatterns = [
    path('',IndexView.as_view(), name='index'),
    # path('blog/<int:pk>/', PostDetailView.as_view(), name="post_detail"),  #これを削除
    path('blog/<slug:slug>/', PostDetailView.as_view(), name="post_detail"), #これを追加
    path('category/<str:category_slug>/',CategoryPostView.as_view(), name='category_post'),
    path('search/', SearchPostView.as_view(), name='search_post'),
]

上記では3、4行目でブログの記事へのURLを定義していますが、

上記の4行目のように<int:pk>が設定されているとブログの末尾が1、2などの数字になります。

4行目の代わりに5行目のように<slug:slug>とすることで記事のURLの末尾をモデルで定義したslugに変えることができます。

最後にindex.htmlなどのhtmlファイルのリンク部分を変えましょう。

HTMLファイルのリンクを書き換える

    {% for item in object_list %}
      <article class="blog-post-box">
        <div class="blog-post-img">
          <a href="{% url 'blogs:post_detail' item.slug %}">  #ここに注目
          {% if item.image %}
            <img src="{{ item.image.url }}" alt="">
          {% endif %}

上記はわたしのブログのindex.htmlの一部ですが、4行目に注目してください。

1行目でListViewで受け取ったobject_list(ブログ記事のデータ)をitemとしてひとつずつ処理していますが、

4行目で詳細記事へ遷移する際にモデルで定義したslugの情報をitem.slugで渡しています。

その後、urls.pyでslug情報を受け取り、URLとして表示します。

以上で設定は終了です。お疲れ様でした。