SlugFieldを使って記事URLの末尾にスラッグを追加した

投稿日:2023年11月6日


背景

従来の当サイトで掲載していた記事のURLは次のような記事IDのみのURLでした。
 https://totlam-wks.com/notes/1/

これだと何の記事なのか分からないので宜しくないそう。(Google SEO的にも非推奨らしい)
それを次のように、URLの末尾に文字列を追加するように変更しました。
 https://totlam-wks.com/notes/1/setup-my-website/

ドメインより後ろの部分(notes以降)をslugというらしいです。
今回、そのslugを変更したときに詰まったというお話。

要件

  • 記事を作成するページにslubを指定する入力欄を追加する。
  • slugだけでURLを生成すると記事数が増えたときに一意性を保つのが面倒臭いので、URLに記事IDも含めることで一意性を確保する

1つめはすんなり実装できましたが、2つめで時間がかかったので備忘録。
時間かかった原因はchatGPTがとんでもない道に誘導してきたことですかね……。

参考になったサイト

Djangoのmodelにおいてslugfieldを使うメリット

NoReverseMatchエラーの対処方【具体的に解説】

もっと色々見たけど最終的にはこの2つだけ読めば解決できていた。

実装

myapp/models.py

class Notes(models.Model):
    title = models.CharField('タイトル', max_length=50)
  :
    slug = models.SlugField(default="", null=False, max_length=50)

 :
 
    def get_absolute_url(self):
        logging.debug(f'[Model]Notes / get_absolute_url called for {self.id, self.slug}.')
        return reverse('myapp:detail', args=[self.id, self.slug])

slugフィールドを追加し、get_absolute_urlメソッドをオーバーライドする。
reverseは名前からurlを呼び出すためのメソッド。便利。
ここのname属性にアプリ名を指定していなかったことで11月の3連休が潰れました。

 NG: reverse('detail', args=[self.id, self.slug])
 OK: reverse('myapp:detail', args=[self.id, self.slug])

エラーとか何も出ずにただただURLが生成されていない状態。
とりあえずget_absolute_urlが呼び出されていないということしか分かりませんでした。

myapp/views.py

viewは変更なし。

myapp/urls.py

path(‘sample/<int:pk>/', views.Detail.as_view(), name='detail'),
↓
path('sample/<int:id>/<slug:slug>/', views.Detail.as_view(), name='detail'),

myapp/templates

<a class="more_link" href="{% url 'myapp:detail' slug=object.slug %}">Read more</a>
 ↓
<a class="more_link" href="{{ object.get_absolute_url }}">Read more</a>

付記

ブログっぽい機能の土台っぽい部分はできたっぽい気がします。
見た目の改善とか検索機能の追加とか色々課題は残ってますが、やりたいことが他にもあるのでその辺りは追々。

chatGPTは便利だけど、メンター代わりに使う場合は気をつけないとですね。
嘘かどうかの判別ができない。逆に、勉強になりますが。

これは泥沼の入り口。まぁ聞き方も悪い。