0
0

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 1 year has passed since last update.

django・Viewクラスの関数のオーバーライドで本来の挙動を変えてることに気づかずエラーにハマってしまった話

Posted at

結論

Viewクラスの関数のオーバーライドすると、実装によっては本来の挙動を変えてしまうこともあります。
それに気づかないとエラーが出てハマることもあるのでこれからは注意しておきたいという記事です。

実際に起きたこと

djangoを使ったコードを書いているときです。
CreateViewを継承した登録用のViewクラスを作成しているところでした。
はじめ、登録成功時のリダイレクトURLをsuccess_urlに格納させることで指定していました。

views.py
class RecordCreateView(CreateView):
    # ...

    # success_urlに格納することでリダイレクトURLを指定
    success_url = reverse_lazy('record_list')

    def form_valid(self, form):
        """
        登録処理
        """
        # ...
        return HttpResponseRedirect(self.success_url)

今後、リダイレクトURLを動的に変更したり、パラメータを付与できるようにしたいと思いました。
そこで、get_success_urlをオーバーライドする方法をとるようにコードを変更しました。

views.py
class RecordCreateView(CreateView):
    # ...

    # success_urlに格納からget_success_url関数をオーバーライドするように変更
    def get_success_url(self):
        return reverse('record_list')

    def form_valid(self, form):
        """
        登録処理
        """
        # ...
        return HttpResponseRedirect(self.success_url)

上記のコードで実際に登録処理を実行しました。すると、登録には成功しました。しかし、「Page not Found」のエラーが発生しました。リダイレクト先もどうやらデフォルトのURLになっているようでした。想定と違う挙動となったため、原因を探る調査をすることにしました。

調査

いろいろな記事を回りましたが、get_success_urlをオーバーライドすることで間違ってはなさそうでした。なのにうまくいかない。そもそもget_success_urlが実行されているかをprintデバッグで試してみたところ、どうやら実行されていない様子。でも、success_urlに値を格納する形だと想定通りの挙動になる。何かおかしいと思いソースコードを眺めていたところ、答えがform_validにありました。

原因

views.py
class RecordCreateView(CreateView):
    # ...

    # success_urlに格納からget_success_url関数をオーバーライドするように変更
    def get_success_url(self):
        return reverse('record_list')

    def form_valid(self, form):
        """
        登録処理
        """
        # ...
        # success_urlにリダイレクトしていたことが原因
        return HttpResponseRedirect(self.success_url)

form_validでHttpResponseRedirectをreturnする処理を書いていたようでした。これにより、引数のURLにリダイレクトすることになります。継承元ではget_success_url関数を呼び出してリダイレクト先を決めているの思います。ですが、それをsuccess_urlで固定するよう上書きしていたため、get_success_url関数が呼び出されることなく想定と違う挙動になってしまっということでした。

原因を踏まえての対応

views.py
class RecordCreateView(CreateView):
    # ...

    def get_success_url(self):
        return reverse('record_list')

    def form_valid(self, form):
        """
        登録処理
        """
        # ...
        # 登録処理を済ませたら継承元の関数に任せるようにする
        return super().form_valid(form)

上記のコードのように、登録処理を済ませた後は継承元の関数に任せるようにしました。これで、無事にget_success_url関数が実行され、関数で返されるURLにリダイレクトできました。

関数のオーバーライドするときは、本来の挙動を変えてしまっていないか、注意していきたいです。

以上です。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?