フロント側でhistory.back()やrequest.META.HTTP_REFERERを使って戻るボタンを実装してみましたが、画面を再表示して戻った時や入力内容の確認画面から戻ってさらに戻る場合などに不都合が発生したため、戻るボタンをView化してみました。
■遭遇した不都合一覧
・検索して一覧表示 → 詳細にとぶ → 戻る → ページネーションが保持されてない(!?)
・一覧の新規登録ボタン押下 → 入力画面 → 確認画面 → 戻る → 入力画面 → 戻る → 確認画面(一覧に戻ってほしかった・・・)
・一覧の新規登録ボタン押下 → 入力画面 → 画面再表示 → 戻る → 入力画面(一覧に戻ってほしかった2・・・)
BaseView
まず、すべてのViewが継承しているBaseViewで、処理後にrequest.META.HTTP_REFERERをリストにつめてセッションに保存処理を追加する。
base/views.py
class BaseView(BaseView):
@classmethod
def view(cls, request, **kwargs):
...
..
.
try:
this.main()
except ApplicationException as ae:
# 業務例外発生時
...
..
.
else:
cls.__update_back_redirect_histories(request) # request.META.HTTP_REFERERをセッションにつめる処理
return this.response()
def __update_back_redirect_histories(request):
""" このメソッド追加
"""
# 戻るボタン押下時は何もしない
if 'back' in request.path:
return
# リファラ(遷移元)をセッションに保存する処理
back_redirect_histories = list()
if 'HTTP_REFERER' in request.META and request.META['HTTP_REFERER']:
# 既に遷移元のリストがセッションに存在する場合はそのリストに追加する。
if 'back_redirect_histories' in request.session:
back_redirect_histories = request.session['back_redirect_histories']
if len(back_redirect_histories) == 0 or back_redirect_histories[-1] != request.build_absolute_uri():
back_redirect_histories.append(request.META['HTTP_REFERER'])
# 遷移元リストを後方から走査し、現在のURLと一致するリファラが見つかった場合、
# リファラの最後尾から見つかった位置までのリファラをリストから削除する。
rm_index = 0
for redirect in reversed(back_redirect_histories):
rm_index += 1
if redirect == request.build_absolute_uri():
rm_index = -rm_index # 正数を負数に変換
break;
if rm_index < 0:
back_redirect_histories = back_redirect_histories[:rm_index]
# 新しい遷移元リストでセッションを更新
request.session['back_redirect_histories'] = back_redirect_histories
戻るボタンのView
common/views.py
from base.views import BaseView
class BackView(BaseView):
""" 戻るボタン押下時のビュークラス
"""
method_only = ['GET']
def main(self):
# セッションから遷移元リストを取得し、最後尾のパスをリダイレクト先に設定する
back_redirect_histories = self.request.session['back_redirect_histories']
self.redirect_to = back_redirect_histories[-1]
urls.pyに戻るボタンのViewを追記
app/urls.py
from django.urls import path
from common.views import BackView
app_name = 'app'
urlpatterns = [
...
..
.
# 戻るボタン(共通)
path('back', BackView.view, name='back'),
]
フロント側の戻るボタンはBackViewを呼び出すだけ
<a href="{% url 'app:back' %}">
<button type="button" >戻る</button>
</a>
備考
みんな戻るボタンどんな風に実装しているんだろうか・・・_φ( ̄ー ̄ )
(Qiita用にBaseViewをかなり書き換えましたが、実際は認証チェックしてたりするので、あしからず。)