sorbans
@sorbans (sorbans base)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

[Django]アドレスバーのURLが更新されない問題について

Q&A

Closed

解決したいこと

Django3.2.5を使っています。

FormViewを継承したクラスからフォーム処理の後にrenderで指定したurlに画面遷移させたいのですが、画面自体は遷移しますが遷移後もブラウザのアドレスバーのurlが遷移元のままなため、リロードすると二重登録されてしまいます。アドレスバーに表示されるurlが遷移先のものになるようにしたいのですがなかなか解決に至りません。
解決に向けたヒントなど頂けましたら幸いです。

views.py

class ShowHogeList(LoginRequiredMixin,ListView):
    model = hogelist
    template_name = 'show_hogelist.html'

    def post(self,request,*args,**kwargs):
        ...
        return self.render_to_response(context)


class PostHoge(LoginRequiredMixin,FormView):
    template_name = 'post_hoge.html'
    form_class = PostHogeForm
    success_url = '/show_hogelist/'

    def form_valid(self,form):
    ...
    return render(self.request,'show_hogelist.html',context)

post_hoge.html


<div>
    <form action="{% url 'hoge:posthoge' %}" method="POST">
        {% csrf_token %}
        {{ form }}
        <button textarea='post_data' formaction='../post_hoge/' type="submit" name="button" value="{'user':'{{user}}',...}">投稿</button>
    </form>
</div>

なお、formacitonはpost_hoge(遷移元のまま)としたいので、show_hegelistに変更せずに対処したいところです。

show_hogelist.html

<ul>
    {% for one in talks %}
        <div>
            {{ one }}
        </div>
    {% endfor %}
</ul>

ここは、単なるリスト表示だけです。この画面に遷移しますが、ブラウザのアドレスバーはpost_hoge.htmlのままです。

自分で試したこと

1週間ネットや書籍を調べ続けましたが、今のところ解決できずにいます。

##よろしくお願いいたします。

0

2Answer

form_valid()で、'show_hogelist.html'を描画してしまっているのが原因です。
この書き方だと、post_hogeのURLでpostした場合に、ページ遷移せず(URLは変わらず)、表示だけlistに書き換わる形になります。

親クラスのFormView.form_valid内で、success_urlにリダイレクトする処理が書かれているので、それを呼び出せば解決します

views.py
class PostHoge(LoginRequiredMixin,FormView):
    template_name = 'post_hoge.html'
    form_class = PostHogeForm
    success_url = '/show_hogelist/'

    def form_valid(self,form):
        ...
        return super().form_valid(form)

1Like

Comments

  1. @sorbans

    Questioner

    Mt_Snow様。

    アドバイスありがとうございました。大変助かりました。
    無事にアドレスバーも遷移先のものに変わるようになりました。
    改めて理解不足を実感致しましたし、とても勉強になりました。

    なおリダイレクトはGETで送られるようですが、これをPOSTに変更する
    方法はあるのでしょうか。status codeが302で返されていたのが原因で
    GETで送信されているのかもしれません。ただこのままですとリダイレクト先
    のdef post()内の処理と同じコードをdef get()で書かなければいけないため
    POSTで送るよう変更できたらと考えています。
    何度も申し訳ありませんが、もし何かヒントになるような事がありましたら
    アドバイスを頂けましたら助かります。
    よろしくお願いいたします。

307でリダイレクトするようにすれば、一応は可能です
FormViewのデフォルトの動きだと、おっしゃる通り302を返すので、リダレクト先には、GETでアクセスされる可能性があります
307に変更すると、フォームにPUSHしたのと同じボディを付与して、リダイレクト先にアクセスします。
https://developer.mozilla.org/ja/docs/Web/HTTP/Status/302

views.py
import HttpResponseRedirectBase from django.http

# 307 Temporary Redirect用のResponseクラスを作成
class HttpResponseTemporaryRedirect(HttpResponseRedirectBase):
    status_code = 307


class PostHoge(LoginRequiredMixin,FormView):
    template_name = 'post_hoge.html'
    form_class = PostHogeForm
    success_url = '/show_hogelist/'

    def form_valid(self,form):
        ...
        # 親クラスのform_vaildでリダイレクトする代わりに、直接307リダイレクトするように変更
        return HttpResponseTemporaryRedirect(self.success_url)

ただ、あまりおすすめはしません。
特別な事情がなければ、GETでもアクセス可能にする方が実装がシンプルですし、そもそもリスト表示の処理のような、データの更新や重たい処理や複雑なリクエストを伴わない処理は、GETを使う方が一般的だと思います。
GETでもアクセス可能にすると以下のような形になります。

views.py
class ShowHogeList(LoginRequiredMixin,ListView):
    model = hogelist
    template_name = 'show_hogelist.html'

    def post(self, request, *args, **kwargs):
        ...
        return self.render_to_response(context)

    def get(self, request, *args, **kwargs):
        # GETでアクセスされたら、post()を呼び出す
        return self.post(request, *args, **kwargs)
``
0Like

Comments

  1. @sorbans

    Questioner

    ポイントを突いたアドバイスを頂き改めてありがとうございました。
    できるだけシンプルになるよう心がけていましたので今回の内容も
    スッと腑に落ちました。
    心から感謝申し上げます。

Your answer might help someone💌