質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.92%

ページ遷移を行なった後、再度POSTリクエストを行いたい

受付中

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 279

study_111

score 75

前提・実現したいこと

現状、index.htmlにて、formからURLを入力し、送信を行うと、「http://127.0.0.1:8000/polls/check/」に遷移します。しかし、そこでリロードをかけると以下のエラーが発生してしまいます。

Page not found (404)
Request Method:    GET
Request URL:    http://127.0.0.1:8000/polls/check/
Using the URLconf defined in wp_tool.urls, Django tried these URL patterns, in this order:

polls/ [name='index']
polls/ <int:question_oo>/ [name='detail']
polls/ check [name='check']
admin/
The current path, polls/check/, didn't match any of these.

You're seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard 404 page.

こちら、GETでのアクセスとなっているのですが、こちらを「POST」リクエストとして、再度formからのリクエストとして、制御したいと考えています。

該当のソースコード

以下は、index.htmlです。

{% load static %}
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="ie=edge"/>
    <link rel="stylesheet" type="text/css" href="{% static 'polls/css/style.css' %}">
    <title>demo</title>
</head>
<body>
    <div class="loader hidden" id="loading">Loading...</div>
    <form id="form" action="{% url 'polls:check' %}" method="post">
        {% csrf_token %}
        <input type="url" name="check_url" placeholder="http://example.com"/>
        <!-- <button type="submit" name="check" value="send">送信</button> -->
        <button type="button" onclick="sendData()">送信</button>
    </form>
    <script src="{% static 'polls/js/app.js' %}"></script>
</body>
</html>


以下は、check.htmlです。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <p>check.htmlです</p>
    <p>{{ alert_msg.err_test }}</p>
</body>
</html>


以下は、views.pyです。

def index(request):
    return render(request,'polls/index.html')
def check(request):

    if request.method == "GET":
        return redirect("polls:index")
    input_url = request.POST['check_url']
    print(input_url)

#諸々の処理

    return render(request,'polls/check.html',{'alert_msg':alert_msg})

以下は、app.jsです。

function showElement(e) {
    e.classList.remove("hidden");
  }

function hideElement(e) {
    e.classList.add("hidden");
}

async function sendData() {

    // ローディング画面を表示する
    showElement(document.getElementById("loading"));

    //formデータを取得
    let formElem = document.getElementById("form")
    // console.log(formElem)
    let formUrl = formElem.action;
    let formData = new FormData(formElem);

    // console.log(formData)

    let response = await fetch(formUrl, {
        method: 'POST',
        body: formData
      });

    // ローディング画面を隠します
    hideElement(document.getElementById("loading"));

    if(response.ok){
        //成功の場合の処理
        console.log(response)
        document.open();
        document.write(await response.text());

        document.close();
        // 前のページへ正しく戻れるようページ歴史に追加する
        history.pushState(null, "", "/polls/check/");

    }else{
        //失敗の場合の処理

    }

  }


追記です
現状、修正を行いたい点がもう一つあります。

以下は、http://127.0.0.1:8000/polls/の画面になります。
イメージ説明
こちらのindex.htmlからformに値を入力し、送信ボタンを押した際には、以下の画面が表示されます。

イメージ説明
こちらのアドレスはhttp://127.0.0.1:8000/polls/check/です。しかし、ブラウザの戻るボタンを押した際にもこちらのcheck.htmlが表示されてしまいます。
イメージ説明
上記画像は、戻るボタンを押した際の画面ですが、http://127.0.0.1:8000/polls/check/で表示されていた内容と同じ内容が表示されてしまっている状況です。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • YufanLou

    2020/07/07 15:19

    追記ありがとうございました。
    問題は末尾のスラッシュです。
    polls/ check [name='check']
    このルートの末尾にスラッシュがないので、
    /polls/check/
    と末尾スラッシュがあるURLでリクエストしたら404が出ます。

    キャンセル

  • study_111

    2020/07/07 15:26 編集

    教えて下さりまして、ありがとうございます。
    urls.pyの部分を「path('check/', views.check, name='check'),」こちらのように、変更しましたらエラーを削除することが出来ました。

    キャンセル

  • study_111

    2020/07/07 15:33 編集

    何度も、お手数をおかけして申し訳ないのですが、実は後、2点程どうしても修正したいポイントがあります。
    そこの部分というのは、本質問にありますリロードした際に「POST」リクエストとしたいといった部分と、もう一点は「http://127.0.0.1:8000/polls/check/」このページにPOSTで遷移した際に、ブラウザの戻るボタンを押しても「check.html」の内容が表示されたままであるという点です。
    こちら、2点目に関しましては、質問内容の方に詳しく記載させて頂きたいと存じます。

    キャンセル

回答 2

0

History API のpushStateを用いて新たなURLを歴史に加えてから、バックの時はindexページを表示したい場合、window.onpopstatewindow.locationdocument.locationで書き換えしてください。

window.onpopstate = function(event) {
  window.location.assign(document.location);
}

追記:問題文のコードはcheck.htmlindex.htmlを書き換えたので、上記のJavaScriptをcheck.htmlに入れてください。

リロードについて追記:

/poll/check でリロードで form データ再送するのを実装します。
まず、どこかで form データを保存しなければならない。History API で歴史 state に form データを保存できます。

// app.js
// ...
async function sendDataOnLoad() {
    //歴史state存在しなかったら中止
    if (!history.state) return;
    //歴史stateからformデータを取得
    let formData = history.state.formData;
    let response = await fetch(formUrl, {
        method: 'POST',
        body: formData
    });
    if(response.ok){
        //成功の場合の処理
        console.log(response)
        document.open();
        document.write(await response.text());
        document.close();
    }else{
        //失敗の場合の処理
    }
}
window.onload = sendDataOnLoad;

サーバーサイドでリダイレクトしたらこのコードを動作しなくなるかもしれないので、Pythonをこう変わります:

// views.py
def check(request):

    if request.method == "GET":
        return render(request, 'polls/index.html')
    # ...

けど、直接にこう実装したら、formデータを送信して、/polls/checkをロードして、formデータを送信して、/polls/checkをロードして…という無限ループになりそうです。

未完成ですが、参考になれたら幸いです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/08 16:45

    >POST使わなくても大丈夫なら、GETを使って、URLにformDataを保存したら、何もしなくてもリロードを越えて保存できます。
    こちら、参考にさせて頂き、試してみたいと存じます。

    キャンセル

  • 2020/07/08 17:23

    > SPAは難易度が高い技術になって来ますでしょうか...?
    JavaScript経験が浅いだとしたらちょっと難しいです。ほぼJavaScriptでやってますから。
    仕事の案件にローディング画面の必要がありましたら仕方ありませんが、そうではない場合は別の機能を先に実装して、どのページが遅いなら特別にそのページでローディング画面を実装する方がいいと思います。
    必要だとしたら、仕方なくJavaScriptを勉強しSPAを作りましょう。 Vue.js などのフレームワークを用いたら楽になります。

    キャンセル

  • 2020/07/08 20:20

    アドバイスありがとうございます。
    SPAを調べてみたのですが、JSのみでも出来なくないみたいですが、フレームワークを使用しなければ難しいようですね。
    今回、ロード画面の実装を考えた経緯は、プログラム側で処理に時間がかかってしまうこともあり、ロード画面があった方が、UX的に良いかなと判断した形でした。
    今回は、ここまで色々と学ばせて頂くことも多かったですし、せっかくなのでVueの学習がてら、SPAでの開発にチャレンジしてみたいとは、考えております。

    キャンセル

0

ページ遷移を行なった後

ページを自動遷移する基本技法でもあるリダイレクト処理は試されたでしょうか。

index.html でフォーム入力し、check.html が表示されてすぐに 再度 index.html を表示するという対応になります。

  1. index.html (フォームを表示するページ)
    input[type=submit] で form[action] の示すURLにPOST要求
  2. check.html (POSTされたデータを処理後に表示される)
    サーバーで入力値を保存するなりして、終わった合図としてページが表示されている

方法としては、3つあります。

  1. check.htmlを応答するのではなく HTTPステータス 301 を応答して index.html にリダイレクトする
  2. check.htmlの load イベントなどに location.href="path/to/index.html" を仕込む
  3. check.htmlに meta[name="refresh"][content="5;http://example.com/path/to/index.html/"]
    (SEO的に待機時間0は非推奨)

Single Page Application であれば YufanLou さんの回答が参考になるはずでした。

追記)

今回の場合は注意メッセージをアラートとして表示させずにformの内容の再送(POSTリクエスト)を行おうと考えています。(コメントより)

ページ遷移による実装ですと、古い「メール送信CGI」の実装事例が近いように思います。

  1. form.html (入力フォーム)
    POSTすると、メール送信せず、確認ページに入力されたデータを埋め込んだフォームのページを応答
  2. check.html (確認ページ+入力フォーム:フィールドは必要に応じてhidden)
    2回目のPOSTでメール送信。
  3. thanks.html (リダイレクト)

※問い合わせ内容のDBへの保存はメールを送信する処理の直前(または直後)に記述。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/08 14:45 編集

    ご追記頂きまして、ありがとうございます。
    > 多重送信の原因になることから、送信後にリダイレクトを利用する方法が使われるようになっています。
    こちらなのですが、今回の場合、問い合わせフォームの送信というよりかは、formから入力された値を元にプログラム側に処理を飛ばし、結果を表示するのみの形で考えておりました。
    具体的には、こちらのサイトのように実装したいと考えております。

    キャンセル

  • 2020/07/08 15:57

    > 具体的には~のように実装したい
    似た実装にしたい場合は、検証ツールで、「どのように実装されているのか」を調査します。
    ざっと確認すると、「フォーム部分は form#scanform[method=GET] であり、 javascriptで onSubmitScanForm() 関数(L38 で読まれた /scripts.min.js内に定義されている)を実行するSPA」実装のようですので、私の回答ではお力になれないようです。

    キャンセル

  • 2020/07/08 16:35 編集

    ご返信ありがとうございます。
    自分でもリンク先を検証ツールで確認するなどし、調べてみます。
    ご親切にご助言頂きまして、ありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.92%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る