結論
Viewクラスの関数のオーバーライドすると、実装によっては本来の挙動を変えてしまうこともあります。
それに気づかないとエラーが出てハマることもあるのでこれからは注意しておきたいという記事です。
実際に起きたこと
djangoを使ったコードを書いているときです。
CreateView
を継承した登録用のViewクラスを作成しているところでした。
はじめ、登録成功時のリダイレクトURLをsuccess_url
に格納させることで指定していました。
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
をオーバーライドする方法をとるようにコードを変更しました。
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
にありました。
原因
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
関数が呼び出されることなく想定と違う挙動になってしまっということでした。
原因を踏まえての対応
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にリダイレクトできました。
関数のオーバーライドするときは、本来の挙動を変えてしまっていないか、注意していきたいです。
以上です。