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

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

ただいまの
回答率

87.61%

Pythonで外部ストレージ内のファイルを実行する方法

解決済

回答 1

投稿 編集

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

score 7

前提・実現したいこと

現在Webアプリケーションを開発しており、「Raspberry pi(以下、ラズパイ)」で「Flask」を利用して開発しています。
ここで、ラズパイ本体に保存されている「app.py」ファイルから外部ストレージとして接続されているUSB内の「message.py」というファイルを実行したいと考えています。
※追記
本問題は、「コード」による問題が原因だと考えています。なので、「外部ストレージ」関連の問題は考慮外であることをお伝えします。しかし、可能性は0では無いので、あくまで問題の本筋を外部ストレージ関連の問題で固定してしまわないようにお願いします。

※ファイルの説明
①「app.py」...ラズパイ本体に保存されている実行ファイル。Web上に用意しているテキストボックスに文字が入力され送信ボタンが押されると、「judg.py」ファイルへ値を送信する。
②「judg.py」...送られてきた値を元に、実行すべきファイルを外部ストレージから探して実行する。(今回は1つだけ)
③「message.py」...外部ストレージ内に入っているアプリケーション。掲示板アプリのようなもの。

発生している問題・エラーメッセージ

期待する動作は、「message」とテキストボックスに打ち込むと「message.py」が起動し、呼び出しているログインページに移動する事です。(出来れば別タブで開きたい...)
現状としては「message」と打ち込み送信すると、エラーなどは起こらないものの、ログインページにジャンプせずに元のページのメッセージ欄に「message is Active」と表示されるだけで終わってしまいます。

該当のソースコード

「app.py」

from flask import Flask, render_template, request
import judg

app = Flask(__name__)
@app.route('/')
def index():
    return render_template('index.html', message="what shall I do?")

@app.route('/', methods=['POST'])
def form():
    field = request.form['field']
    if request.method == 'POST':
        res = judg.judg(field)
    return render_template('index.html', message=res['msg'], answer=res['ans'])

if __name__=='__main__':
    app.run(debug=True, host='localhost')


「judg.py」

from flask import Flask, render_template, request, redirect
import os, sys
//外部ストレージとのパスを通す
sys.path.append(os.path.join(os.path.dirname(__file__), '/media/pi/NAS')) 
import message

app = Flask(__name__)
@app.route('/')
def judg(field):
    if "message" in field:
        res = {'msg':"What shall I do?", 'ans':"message is Active!"}
        message.login()
        return res
    else:
        res = {'msg':"What shall I do?", 'ans':"Sorry.."}
        return res


「message.py」

from flask import Flask, render_template, request, session, redirect


app = Flask(__name__)
app.secret_key = b'abc'

member_data = {}
message_data = []

@app.route('/', methods=['GET'])
def index():
    global message_data
    if 'login' in session and session['login']:
        msg = 'Login id:' + session['id']
        return render_template('messages.html',
                               title='Messages',
                               message=msg,
                               data=message_data )
    else:
        return redirect('/login')

@app.route('/', methods=['POST'])
def form():
    msg = request.form.get('comment')
    message_data.append((session['id'], msg))
    if len(message_data) > 25:
        message_data.pop(0)
    return redirect('/')

#login page access
@app.route('/login', methods=['GET'])
def login():
    return render_template('login.html',
                           title='Login',
                           err=False,
                           message='IDとパスワ−ドを入力:',
                           id='' )

#login
@app.route('/login', methods=['POST'])
def login_post():
    global member_data
    id = request.form.get('id')
    pswd = request.form.get('pass')
    if id in member_data:
        if pswd == member_data[id]:
            session['login'] = True
        else:
            session['login'] = False
    else:
        member_data[id] = pswd
        session['login'] = True
    session['id'] = id
    if session['login']:
        return redirect('/')
    else:
        return render_template('login.html',
                               title='Login',
                               err=False,
                               message='パスワードが違います。',
                               id=id )

#logout
@app.route('/logout', methods=['GET'])
def logout():
    session.pop('id', None)
    session.pop('login')
    return redirect('/login')

if __name__== '__main__':
    app.run(debug=True, host='localhost', port=5000)

「layout.html」

<!doctype html>
<html lang="ja">
<head>
    <title>{% block titile %}{% endblock %}</title>
    <meta charset="utf-8"/>
    <link rel="stylesheet"
        href="{{url_for('static', filename='style.css')}}">
</head>
<body>
    <h1>{% block headline %}{% endblock %}</h1>

    {% block content %}{% endblock %}

    <div class="footer">
        {% block footer %}{% endblock %}
    </div>
</body>
</html>

「index.html」

{% extends "layout.html" %}

{% block title %}
index
{% endblock %}

{% block headline %}
Web Server
{% endblock %}

{% block content %}
<p>{{ message }}</p>
<div>
    <form method="post" action="/" >
        <input type="text" name="field">
        <input type="submit" name="send" value="送信">
    </form>
</div>
<p>Answer = {{ answer }}</p>
{% endblock %}

{% block footer %}
RURSystem.
{% endblock %}

「login.html」

{% extends "layout.html" %}

{% block title %}
Login
{% endblock %}

{% block headline %}
{{ title }}
{% endblock %}

{% block content %}
<p>{{ message }}</p>
<form method="post" aciton="/login">
<table>
    <tr>
        <th>id</th>
        <td>
            <input type="text" name="id" value="{{id}}">
        </td>
    </tr>
    <tr>
        <th>password</th>
        <td>
            <input type="password" name="pass">
        </td>
    </tr>
    <th></th><td>
        <input type="submit" value="Login">
    </td>
    </div>
</form>
</table>
{% endblock %}

{% block footer %}
RURSystem_Message board.
{% endblock %}

「messages.html」

{% extends "layout.html" %}

{% block title %}
Message
{% endblock %}

{% block headline %}
{{ title }}
{% endblock %}

{% block content %}
<div class="logout"><a href="logout">Logout</a></div>
<p>{{ message }}</p>
<form method="post" action="/">
    <table>
        <tr>
            <th>Message</th>
            <td>
                <input type="text" name="comment" width="80">
            </td>
            <td>
                <input type="submit" value="POST NOW">
            </td>
        </tr>
    </table>
</form>
<hr>
<ul>
{% for item in data | reverse %}
    <li>{{item[1]}} ({{item[0]}})</li>
{% endfor %}    
</ul>
{% endblock %}

{% block footer %}
tasojiro.
{% endblock %}

「style.css」

body{
    margin: 10px;
    background-color: aliceblue;
    }
h1{
    color: lightsteelblue;
    font-size: 36pt;
    margin:0px;
    }
p{
    font-size: 14pt;
    }
pre{
    background-color: white;
    font-size: 12pt;
    padding: 10px;
    }
div.footer{
    text-align: right;
    border-bottom: 1px solid lightskyblue;
    color: lightskyblue;
    margin: 50px 0px;
    }
div.logout{
    position: absolute;
    right: 10px;
    top: 10px;
    font-weight: bold;
    font-size: 12pt;
    }

ディレクトリ構成

「WebServer」 
→(app.py)
→(judg.py) 
→(「templates」 →login.html, layout.html, index.html)
→(「static」 →style.css)

「Skills」(外部ストレージ(USB内))
→(message.py)
→(「templates」 →layout.html, message.html)
→(「static」 →style.css)

最後に

Webアプリケーションは、まだ初心者なので間違っている事があれば指摘していただけると幸いです。
何か情報が不足している場合は、言っていただけると追加します。
よろしくお願いします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • tasojiro

    2020/10/27 17:51

    もしかしたら、flaskやpythonの有識者が現在模索しているコードを示して頂ける可能性がありますので、引き続きオープンにしたいと思います。

    キャンセル

  • ebal

    2020/10/27 19:30

    横から失礼します.コードを期待するならば最低でもテンプレートとして使っているindex.htmlも(あとおそらくlayout.htmlも)示したほうが良いかと思われます.

    キャンセル

  • tasojiro

    2020/10/27 20:22

    確かに、HTMLファイルを示した方が良かったですね。追記しておきます。
    ありがとうございます。

    キャンセル

回答 1

checkベストアンサー

0

しばらく見ていましたが回答が付かないようなので、方針だけ回答します。
(tasojiroさんが何をやりたいのか、質問文とソースコードから理解できなかったので、方針だけです。)

Flaskでのソースコードの分け方

ソースコードだけ見ると、app.py, judg.py, message.pyは全部別のサイトです。
(Blueprintが使われておらず、エンドポイントが重複しているので別サイトにしないとアクセスできないはず)無理矢理importされていたりしますが、期待通りの動作にならないと思います。

app.py, judg.py, templates/index.html, templates/layout.htmlだけを使ってapp.pyを実行すると、judg(field)に対応したエンドポイントにアクセスできないはずです。
Flaskでソースコードを分ける場合はBlueprintを使ってください。

Blueprintについては、以下のドキュメントが参考になります。
Modular Applications with Blueprints

Blueprintを使う事により、以下のプログラムは1つのWebページとして実行できるはずです。

  • app.py
  • judg.py
  • templates/index.html
  • templates/layout.html
  • static/style.css

message.pyは別サイトになると思うので、以下を参照ください。

message.pyについて

「app.py」ファイルから外部ストレージとして接続されているUSB内の「message.py」というファイルを実行したいと考えています。

という記述がありますが、message.pyを見ると、Flaskで作成されているようです。
つまり、message.pyはWebサイトである事がわかります。

Webサイトであるなら、app.pyがmessage.pyを実行するということは行いません。
Webサイトはgunicornなどで起動され、ずっと動いているのが通常だからです。
(別途Apacheやnginxをフロントに配置)

いまのところ、以下のWebサイトがあるはずです。
Webサイト1: app.py + judg.py
Webサイト2: message.py

Webサイト1とWebサイト2は別のWebサイトなので、連携にはHTTPを使います。
judg.pyにあるimport messagesys.path.append(os.path.join(os.path.dirname(__file__), '/media/pi/NAS')) は書きません。
HTTPを使ったリクエスト/レスポンスをpythonで実装するなら、requestsを使うのが簡単です。
requestsを使って連携するなら、現状のrender_templateを返すものより、REST APIとして作り直した方が使いやすいかもしれません。
どちらにしろ、requestsで得た結果をjudg()関数内などで判断すれば良いと思います。

最後に、HTMLやcssが共有(style.cssやlayout.html)と思いますが、Webサイトが2つあるので二重管理が必要になります。
後々になってミスが起こったりしそうなので、リスク低減のために同一サイトにした方が良いと思います。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/10/31 13:00

    回答ありがとうございます。

    実現したいこととしては、一言でいうと「webページからキーワードを入力することで、キーワードに対応したプログラムを起動する」という事です。このプログラムというのは、外部接続されたUSB内の自作プログラムに当たります。

    今回は、この自作プログラムが「message.py」というwebアプリでしたが、メモ帳などの自作したプログラムがUSB内に入っていれば(webアプリではないプログラムという事です)これを起動できるようなものを考えております。

    ・Flaskでのコードの分け方について。
    「Blueprint」を使用して、調べながら作成し直したいと思います。ありがとうございます。

    ・message.pyについて。
    別サイトとして考え、サイトからサイトへ「requests」を使用して連携するという事ですね。
    参考にして考え直したいと思います。

    最後に、同一サイトにした方がいいとは、どういう事でしょうか?先まで別サイトとして考えるとありましたが、そもそもこの別サイトとして考えるのはやめた方がいいという事でしょうか?

    キャンセル

  • 2020/12/05 20:41

    「Blueprint」を利用すると解決できました。
    この案をいただいたので、BAとさせていただきます。

    キャンセル

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

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

関連した質問

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