11
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Djangoで戻るボタン用のViewを実装してみた。

Last updated at Posted at 2019-08-22

フロント側で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をかなり書き換えましたが、実際は認証チェックしてたりするので、あしからず。)

11
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?