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

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

ただいまの
回答率

90.50%

  • Python

    8007questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Cloud9

    428questions

    Cloud9は、クラウドからのプログラミングが可能になるWebサービス。IDEとしての機能が搭載されており、GitHubやHerokuなど他ツールとの連携も可能です。ブラウザ上で動くため、デバイスに関係なく開発環境を準備できます。

  • Flask

    211questions

    FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Flaskでアプリを作成しHerokuにデプロイしたが、sessionが途中で切れてしまう

解決済

回答 1

投稿 編集

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

nokonoko_1203

score 11

いつも大変お世話になっております。

表記の件について、AWS Cloud9環境にてFlaskアプリを作成しHerokuデプロイしましたが、sessionが切れたり、リロードしたら戻ってきたりとおかしな挙動をしています。

cloud9でのプレビューでは、問題ないのですが、Herokuにデプロイしたものが同様の動きをせず困っております。

特にログイン後の「edit.html」から「index.html」にリダイレクトするときや、「index.html」で再読み込みをするときに頻発しております。

#!/usr/bin/env python
# coding: utf-8

import sqlite3
from flask import Flask, render_template, request, redirect, url_for, session, flash
# from flask.ext.session import Session は廃止されている
from flask_session import Session
import os


app = Flask(__name__)
app.secret_key = os.urandom(24)
SESSION_TYPE = 'filesystem'
app.config.from_object(__name__)
sess = Session()

sqlite_path = 'db/stockpile.db'
users_db_path = 'db/users.db'


def get_db_connection():
    connection = sqlite3.connect(sqlite_path)
    connection.row_factory = sqlite3.Row
    return connection

def get_user_db_connection():
    connection = sqlite3.connect(users_db_path)
    connection.row_factory = sqlite3.Row
    return connection


@app.before_request
def before_request():
    # # 静的ファイルへのアクセスについては、チェック対象としない
    # if request.path.startswith('/static/'):
    #     return
    # セッションにusernameが保存されている.つまりログイン済み
    if session.get("username") == "admin":
        return
    # リクエストパスがログインページに関する場合
    if request.path == '/login':
        return
    # ログインされておらず,インデックスに関するリクエストの場合
    if request.path == '/':
        return
    # ログインされておらず,ログインページに関するリクエストでない場合
    return render_template('index.html')


@app.route("/")
def index():
    if session.get("username") == "admin":
        connection = get_db_connection()
        cursor = connection.cursor()
        res = cursor.execute('SELECT * FROM stockpile')
        return render_template('index.html', stock_list=res.fetchall(),
        username=session["username"], password=session["password"])
    else:
        connection = get_db_connection()
        cursor = connection.cursor()
        res = cursor.execute('SELECT * FROM stockpile')
        return render_template('index.html', stock_list=res.fetchall())


# 個人認証を行い,正規のアカウントか確認する
def _is_account_valid():
    username = request.form.get('username')
    password = request.form.get("password")
    # この例では,ユーザ名にadminが指定されていれば正規のアカウントであるとみなしている
    # ここで具体的な個人認証処理を行う.認証に成功であればTrueを返すようにする
    if username == 'admin' and password == 'admin':
        session["username"] = username
        return True
    return False


@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == 'POST':
        error = []
        username = request.form.get("username", None)
        password = request.form.get("password", None)
        if username == "":
            error.append("名前を入力して下さい")
        if password == "":
            error.append("パスワードを入力して下さい")

        if error:
            stockpile = request.form.to_dict()
            return render_template("login.html", error_list=error)

        if _is_account_valid():
            session["username"] = username
            session["password"] = password
            flash('ログインしました', 'info')
            return redirect(url_for('index'))

        error.append("組み合わせが正しくありません")
        return render_template("login.html", error_list=error) 


    elif request.method == 'GET':
        return render_template("login.html")

    else:
        return render_template("index.html")


@app.route("/logout")
def logout():
    session.pop("username", None)
    return render_template("index.html")


@app.route("/add", methods=["GET", "POST"])
def add_stock():
    if request.method == "GET":
        """移動先のテンプレートがformの中で辞書(stockpile)を使ってるから、
        からのリストを定義しておかないとエラー発生
        """
        stockpile = {}
        return render_template("edit.html", type="add", stockpile=stockpile)
    elif _is_account_valid():
        connection = get_db_connection()
        cursor = connection.cursor()
        error = []

        if not request.form["name"]:
            error.append("商品名を入力して下さい")
        if not request.form["stocknumber"]:
            error.append("個数を入力して下さい")
        if not request.form["duedate"]:
            error.append("賞味期限を入力して下さい")

        if error:
            #name属性をkey,入力をvalueにした辞書を作成?
            stockpile = request.form.to_dict()
            return render_template("edit.html", type="add", stockpile=stockpile, error_list=error)

        cursor.execute("INSERT INTO stockpile(name, stocknumber, duedate, memo) VALUES(?, ?, ?, ?)",
                      (request.form["name"], 
                       request.form["stocknumber"],
                       request.form["duedate"],
                       request.form["memo"]))
        connection.commit()
        return redirect(url_for('index'))


@app.route("/delete/<int:id>")
def delete(id):
    connection = get_db_connection()
    cursor = connection.cursor()
    cursor.execute("DELETE FROM stockpile WHERE id = ? ", (id,))
    connection.commit()
    return render_template("index.html")


@app.route("/edit/<int:id>")
def edit(id):
    connection = get_db_connection()
    cursor = connection.cursor()
    res = cursor.execute("SELECT * FROM stockpile WHERE id = ? ", (id,))
    return render_template("edit.html", type="edit", stockpile=res.fetchone())


@app.route("/update/<int:id>", methods=["POST"])
def update_stock(id):
        error = []

        if not request.form["name"]:
            error.append("商品名を入力して下さい")
        if not request.form["stocknumber"]:
            error.append("個数を入力して下さい")
        if not request.form["duedate"]:
            error.append("期限を入力して下さい")

        if error:
            stockpile = request.form.to_dict()
            return render_template("edit.html", type="edit", stockpile=stockpile, error_list=error)

        connection = get_db_connection()
        cursor = connection.cursor()
        cursor.execute("UPDATE stockpile set name = ? , stocknumber = ? , duedate = ? , memo = ?  where id = ?",
                      (request.form["name"],
                       request.form["stocknumber"],
                       request.form["duedate"],
                       request.form["memo"],
                       id))
        connection.commit()
        return redirect(url_for("index"))


if __name__ == '__main__':
    # app.debug = True # デバッグモード有効化
    # どこからでもアクセス可能に
    app.run(host='0.0.0.0', port=8080, threaded=True)
{% extends "layout.html" %}
{% block body %}
<body>
    {% for message in get_flashed_messages() %}
    <div class="alert alert-warning">
    {{ message }}
    </div>
    {% endfor %}
    <h1>在庫管理 アプリケーション</h1>
    {% if session.username == "admin" %}
    <table>
        <tr>
            <th>商品名</th>
            <th>個数</th>
            <th>賞味期限</th>
            <th>メモ</th>
            <th></th>
        </tr>
        {% for v in stock_list %}
        <tr>
            <td><a href="{{ url_for('edit', id=v['id'])}}">{{ v['name']}}</a></td>
            <td>{{ v['stocknumber']}}</td>
            <td>{{ v['duedate']}}</td>
            <td>{{ v['memo']}}</td>
            <td><a href={{ url_for("delete", id=v["id"]) }}>削除</a></td>
        </tr>
        {% endfor %}
    </table>
    <h3><a href="{{ url_for('add_stock')}}">在庫の追加</a></h3>
    <h3><a href="{{ url_for('logout')}}">ログアウト</a></h3>
    {% else %}
    <h3><a href="{{ url_for('login')}}">ログイン</a></h3>
    {% endif %}
</body>
{% endblock %}
{% extends "layout.html" %}
{% block body %}
<body>

    <h1>在庫を編集する</h1>

    <form method="post" action="{% if type == "add" %}{{ url_for('add_stock') }}{% else %}{{ url_for('update_stock', id=stockpile["id"]) }}{% endif %}">
        {% if error_list %}
        <ul>
        {% for v in error_list %}
            <li>{{ v }}</li>
        {% endfor %}
        </ul>
        {% endif %}
        <p>商品名<br/><input type="text" name="name" value="{{ stockpile['name'] }}"/></p>
        <p>在庫数<br/><input type="int" name="stocknumber" value="{{ stockpile['stocknumber'] }}"/></p>
        <p>期限<br/><input type="text" name="duedate" value="{{ stockpile['duedate'] }}"/></p>
        <p>メモ<br/><input type="text" name="memo" value="{{ stockpile['memo'] }}" size="60"/></p>
        {% if type == "add" %}
        <button type="submit">在庫を追加</button>
        {% else %}
        <button type="submit">在庫を更新</button>
        {% endif %}
    </form>
    <br/>
    <a href="{{ url_for('index')}}">トップに戻る</a>
</body>
{% endblock %}

調べてみた限りではredisを利用してsessionをデータベースに保存するのがいいようなことはわかったのですが、Railsでのやり方や、英語のドキュメントしか見当たらず、理解することができませんでした。

ご教示いただけると幸いです。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+1

以前Herokuでflaskを動かしたときsecret_keyがランダムだと正常に動作しなかったので多分それじゃないかと。違ってたらすみません。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/05/23 20:37

    解決いたしました!!!
    本当にありがとうございました!

    キャンセル

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

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

関連した質問

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

  • Python

    8007questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Cloud9

    428questions

    Cloud9は、クラウドからのプログラミングが可能になるWebサービス。IDEとしての機能が搭載されており、GitHubやHerokuなど他ツールとの連携も可能です。ブラウザ上で動くため、デバイスに関係なく開発環境を準備できます。

  • Flask

    211questions

    FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。