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

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

新規登録して質問してみよう
ただいま回答率
85.35%
Flask

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

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Python

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

Q&A

解決済

1回答

1816閲覧

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

tasojiro

総合スコア16

Flask

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

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Python

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

0グッド

0クリップ

投稿2020/10/27 01:46

編集2020/10/27 11:28

前提・実現したいこと

現在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」

Python

1from flask import Flask, render_template, request 2import judg 3 4app = Flask(__name__) 5@app.route('/') 6def index(): 7 return render_template('index.html', message="what shall I do?") 8 9@app.route('/', methods=['POST']) 10def form(): 11 field = request.form['field'] 12 if request.method == 'POST': 13 res = judg.judg(field) 14 return render_template('index.html', message=res['msg'], answer=res['ans']) 15 16if __name__=='__main__': 17 app.run(debug=True, host='localhost')

「judg.py」

Python

1from flask import Flask, render_template, request, redirect 2import os, sys 3//外部ストレージとのパスを通す 4sys.path.append(os.path.join(os.path.dirname(__file__), '/media/pi/NAS')) 5import message 6 7app = Flask(__name__) 8@app.route('/') 9def judg(field): 10 if "message" in field: 11 res = {'msg':"What shall I do?", 'ans':"message is Active!"} 12 message.login() 13 return res 14 else: 15 res = {'msg':"What shall I do?", 'ans':"Sorry.."} 16 return res

「message.py」

Python

1from flask import Flask, render_template, request, session, redirect 2 3 4app = Flask(__name__) 5app.secret_key = b'abc' 6 7member_data = {} 8message_data = [] 9 10@app.route('/', methods=['GET']) 11def index(): 12 global message_data 13 if 'login' in session and session['login']: 14 msg = 'Login id:' + session['id'] 15 return render_template('messages.html', 16 title='Messages', 17 message=msg, 18 data=message_data ) 19 else: 20 return redirect('/login') 21 22@app.route('/', methods=['POST']) 23def form(): 24 msg = request.form.get('comment') 25 message_data.append((session['id'], msg)) 26 if len(message_data) > 25: 27 message_data.pop(0) 28 return redirect('/') 29 30#login page access 31@app.route('/login', methods=['GET']) 32def login(): 33 return render_template('login.html', 34 title='Login', 35 err=False, 36 message='IDとパスワ−ドを入力:', 37 id='' ) 38 39#login 40@app.route('/login', methods=['POST']) 41def login_post(): 42 global member_data 43 id = request.form.get('id') 44 pswd = request.form.get('pass') 45 if id in member_data: 46 if pswd == member_data[id]: 47 session['login'] = True 48 else: 49 session['login'] = False 50 else: 51 member_data[id] = pswd 52 session['login'] = True 53 session['id'] = id 54 if session['login']: 55 return redirect('/') 56 else: 57 return render_template('login.html', 58 title='Login', 59 err=False, 60 message='パスワードが違います。', 61 id=id ) 62 63#logout 64@app.route('/logout', methods=['GET']) 65def logout(): 66 session.pop('id', None) 67 session.pop('login') 68 return redirect('/login') 69 70if __name__== '__main__': 71 app.run(debug=True, host='localhost', port=5000)

「layout.html」

HTML

1<!doctype html> 2<html lang="ja"> 3<head> 4 <title>{% block titile %}{% endblock %}</title> 5 <meta charset="utf-8"/> 6 <link rel="stylesheet" 7 href="{{url_for('static', filename='style.css')}}"> 8</head> 9<body> 10 <h1>{% block headline %}{% endblock %}</h1> 11 12 {% block content %}{% endblock %} 13 14 <div class="footer"> 15 {% block footer %}{% endblock %} 16 </div> 17</body> 18</html>

「index.html」

HTML

1{% extends "layout.html" %} 2 3{% block title %} 4index 5{% endblock %} 6 7{% block headline %} 8Web Server 9{% endblock %} 10 11{% block content %} 12<p>{{ message }}</p> 13<div> 14 <form method="post" action="/" > 15 <input type="text" name="field"> 16 <input type="submit" name="send" value="送信"> 17 </form> 18</div> 19<p>Answer = {{ answer }}</p> 20{% endblock %} 21 22{% block footer %} 23RURSystem. 24{% endblock %}

「login.html」

HTML

1{% extends "layout.html" %} 2 3{% block title %} 4Login 5{% endblock %} 6 7{% block headline %} 8{{ title }} 9{% endblock %} 10 11{% block content %} 12<p>{{ message }}</p> 13<form method="post" aciton="/login"> 14<table> 15 <tr> 16 <th>id</th> 17 <td> 18 <input type="text" name="id" value="{{id}}"> 19 </td> 20 </tr> 21 <tr> 22 <th>password</th> 23 <td> 24 <input type="password" name="pass"> 25 </td> 26 </tr> 27 <th></th><td> 28 <input type="submit" value="Login"> 29 </td> 30 </div> 31</form> 32</table> 33{% endblock %} 34 35{% block footer %} 36RURSystem_Message board. 37{% endblock %}

「messages.html」

HTML

1{% extends "layout.html" %} 2 3{% block title %} 4Message 5{% endblock %} 6 7{% block headline %} 8{{ title }} 9{% endblock %} 10 11{% block content %} 12<div class="logout"><a href="logout">Logout</a></div> 13<p>{{ message }}</p> 14<form method="post" action="/"> 15 <table> 16 <tr> 17 <th>Message</th> 18 <td> 19 <input type="text" name="comment" width="80"> 20 </td> 21 <td> 22 <input type="submit" value="POST NOW"> 23 </td> 24 </tr> 25 </table> 26</form> 27<hr> 28<ul> 29{% for item in data | reverse %} 30 <li>{{item[1]}} ({{item[0]}})</li> 31{% endfor %} 32</ul> 33{% endblock %} 34 35{% block footer %} 36tasojiro. 37{% endblock %}

「style.css」

CSS

1body{ 2 margin: 10px; 3 background-color: aliceblue; 4 } 5h1{ 6 color: lightsteelblue; 7 font-size: 36pt; 8 margin:0px; 9 } 10p{ 11 font-size: 14pt; 12 } 13pre{ 14 background-color: white; 15 font-size: 12pt; 16 padding: 10px; 17 } 18div.footer{ 19 text-align: right; 20 border-bottom: 1px solid lightskyblue; 21 color: lightskyblue; 22 margin: 50px 0px; 23 } 24div.logout{ 25 position: absolute; 26 right: 10px; 27 top: 10px; 28 font-weight: bold; 29 font-size: 12pt; 30 } 31

###ディレクトリ構成
「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アプリケーションは、まだ初心者なので間違っている事があれば指摘していただけると幸いです。
何か情報が不足している場合は、言っていただけると追加します。
よろしくお願いします。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2020/10/27 02:20

Flaskを知っている訳ではないのですが、judg.py の > sys.path.append(os.path.join(os.path.dirname(__file__), '/media/pi/NAS')) の部分、os.path.join(os.path.dirname(__file__), '/media/pi/NAS') この操作は正しいのでしょうか? この呼び出しの返り値で意図通りのものが返ってきていますか? あと、外部ストレージ特有の問題なのか、外部ストレージに限らずそもそも別のディレクトリに配置すると動かないのかどうか確認した方が良いと思います。
tasojiro

2020/10/27 02:35

回答ありがとうございます。 > sys.path.append(os.path.join(os.path.dirname(__file__), '/media/pi/NAS') この部分ですが、実行コードのあるディレクトリからラズパイに接続されたUSB内のディレクトリを参照する為に必要なコードとなります。 これがないと、ディレクトリまでのパスが通らず実行できない状態になってしまいます。 >あと、外部ストレージ特有の問題なのか、外部ストレージに限らずそもそも別のディレクトリに配置すると動かないのかどうか確認した方が良いと思います。 別のディレクトリに配置した場合ですが、実行ファイルのカレントディレクトリに移して試しても、質問時と同様の動作になることを確認しています。(他の場所でも同様です。一番可能性のあるカレントディレクトリで試してみました。) 個人的には、やはりコードに問題があるのかなと感じています。特に、呼び出しを行っている「judg.py」ファイルの「message.login()」の部分です。 しかしエラーは出ないので、「コードが間違っている」ではなく、「message.pyの結果を表示するコードがどこかに足りない」のかなとも考えています。
dodox86

2020/10/27 02:41

> 実行コードのあるディレクトリからラズパイに接続されたUSB内のディレクトリを参照する為に必要なコードとなります。 これがないと、ディレクトリまでのパスが通らず実行できない状態になってしまいます。 いえ、importに関わっている、それは分かっているのですけど、os.path.join(os.path.dirname(__file__), '/media/pi/NAS') で生成されたPATHは正しいですか?という指摘です。 > 別のディレクトリに配置した場合ですが、実行ファイルのカレントディレクトリに移して試しても、質問時と同様の動作になることを確認しています。 正直、そうだと思っていました。質問文に「外部ストレージ云々」と書くと、私を含む多くの閲覧者、回答者は「外部ストレージ特有の問題か?」と考えます。外部ストレージであると、USBドライブのマウントのタイミングの問題が関係することがあります。その懸念を払底するための指摘です。問題の切り分けに重要な情報なのでそれは質問文中に記載すべきでしょう。
tasojiro

2020/10/27 03:39

>os.path.join(os.path.dirname(__file__), '/media/pi/NAS') で生成されたPATHは正しいですか?という指摘です。 勘違いをしてしまいました。。すみません。 生成されたPATHが正しいかという事ですが、print(path)で見てみたところ「/media/pi/NAS」となっていました。これは、正しくない結果でしょうか? NASまでのPATHが通っていることから、正しいと思っていたのですが… >外部ストレージであると、USBドライブのマウントのタイミングの問題が関係することがあります。その懸念を払底するための指摘です。問題の切り分けに重要な情報なのでそれは質問文中に記載すべきでしょう。 確かに、わざわざ「外部ストレージ」と書いてしまうとそこに原因を模索してしまうかもしれませんね。 質問文に追加しておきたいと思います。ご指摘ありがとうございます。
dodox86

2020/10/27 04:45

> print(path)で見てみたところ「/media/pi/NAS」となっていました。これは、正しくない結果でしょうか? 結果的に /media/pi/NAS/ディレクトリが正しいのであればそれで結構です。指摘したのは os.path.join(os.path.dirname(__file__), '/media/pi/NAS') とのように、 os.path.dirname(__file__)のディレクトリPATHとjoinしているので、それは意図として正しいのか? ということです。__file__ をos.path.dirname(__file__) すると結果的に空文字になっているので、joinしても"/media/pi/NAS" になったままなのでしょう。 あと、`judg`関数のコードを見ると 以下のようになっていて、`message.login()`の結果を返していません。`res`をそのまま`return`しています。 if "message" in field: res = {'msg':"What shall I do?", 'ans':"message is Active!"} message.login() return res 少なくともmessage.pyのlogin関数の実行結果、つまりhtmlの内容を返すことでブラウザにそれが表示される流れになるはずですから、 if "message" in field: # res = {'msg':"What shall I do?", 'ans':"message is Active!"} res = message.login() return res のように返す必要があるのでは?当方にFlaskの検証環境はないので外している可能性もあり、外していないとしても他の部分で修正しなければいけない気もするので、以上コメントのみです。
tasojiro

2020/10/27 05:13

>os.path.join(os.path.dirname(__file__), '/media/pi/NAS') とのように、os.path.dirname(__file__)のディレクトリPATHとjoinしているので、それは意図として正しいのか? ということです。 joinすることでパスが通るのであれば、自分が意図していることなので大丈夫です。 >少なくともmessage.pyのlogin関数の実行結果、つまりhtmlの内容を返すことでブラウザにそれが表示される流れになるはずですから、 if "message" in field: # res = {'msg':"What shall I do?", 'ans':"message is Active!"} res = message.login() return res のように返す必要があるのでは? 自分も回答者さんのように「message.pyのlogin関数の実行結果、つまりhtmlの内容を返すことでブラウザにそれが表示される流れになるはず」と思っていて、message.pyのlogin関数の実行結果はmessage.py側で返すものだと思っていました。 回答者さんのように「res」に関数の実行結果を載せると、「app.py」側での受け取り方(表示の仕方?)がどのようにすれば良いか想像がつかないのですが、どのようになるか分かりますでしょうか。
dodox86

2020/10/27 05:18

> どのようになるか分かりますでしょうか。 judg()のルーティングの指定には@app.route('/')となっているので、WEBブラウザが/ に対するHTTPリクエストをし、judg関数がreturnして吐き出す内容がWEBブラウザにHTTPレスポンスとして返されます。それがHTMLならHTMLでブラウザ上に表示されます。Flaskでも基本、そのような流れのはずです。
tasojiro

2020/10/27 05:28

つまり、judg関数がHTMLである以上、受け取るapp.py側はその受けとったHTMLファイルを表示するコードが必要という解釈でよろしいでしょうか。 もしもこれで成功したとして。この場合、初めにテキストボックスに文字列を書き送信していた画面に上書きされる形で表示されるのでしょうか?別タブで表示ことはできませんか?
dodox86

2020/10/27 05:34

表示するのはあくまでブラウザ側の仕事です。Flaskを使ったWEBサーバーはHTTPレスポンスとして返すだけです。別タブで表示するには、ブラウザにそのような挙動をさせるHTTPレスポンス、必要であればブラウザから再びHTTPリクエストを投げてくるようなものを返す必要があるはずです。具体的なコードはFlaskを検証できる環境にないので、すみませんがご提供できません。あまり混乱させても悪いので、Flaskの動作に知見のある方のご回答をお待ちください。
tasojiro

2020/10/27 07:28

「別タブで表示するには、ブラウザにそのような挙動をさせるHTTPレスポンス、必要であればブラウザから再びHTTPリクエストを投げてくるようなものを返す必要があるはずです。」とのことですが、このような挙動はHTMLファイルに書き込む必要があるものですか? それともWEBサーバーとして稼働させている実行ファイル(app.py)でしょうか? (HTTPレスポンス及びHTTPリクエストは、POST/GET通信を行っている実行ファイルだからこちらかな?と考えます…) 具体的なコードは、上記の疑問が解決して「別タブで表示する為に行う方針」を定めてから、改めて別枠で質問してみようと思います。ありがとうございます。
dodox86

2020/10/27 08:07

> このような挙動はHTMLファイルに書き込む必要があるものですか? まぁ、そういうことになります。WEBブラウザは、受信したHTTPレスポンスのコンテントボディ部に格納されたHTMLを表示するわけですが、そのHTMLを解釈するときに新たにウィンドウを開くタイミングの処理をJavaScriptで記述することで別のタブに別のhtmlを表示するよう、誘導することができます。 「WEBブラウザ 別タブで開く」などで検索すれば関連情報がヒットします。 <a>アンカータグの「target="_blank"」なども検索してみてください。 「別タブで開く」については、本来はまじめに対応するとセキュリティ面での配慮も必要になります。 > それともWEBサーバーとして稼働させている実行ファイル(app.py)でしょうか? 何と言いますか、@app.routeのアノテーションで指定された関数で返す文字列がHTMLで返信される訳ですので、それを満たせばどちらでも、と言っていいです。FlaskはテンプレートファイルからもHTMLを生成していますね。
tasojiro

2020/10/27 08:22

選択肢として、 1「HTMLファイルに、別タブで表示する為の挙動(具体的には「target="_blank"」)を記述する」 2「HTMLではなく@app.routeのデコレータで挙動を変える」 の2つがあると解釈してよろしいでしょうか? 過去に、別タブで表示する為に調べ「target="_blank"」をHTMLにいれて試したことがあります。 結果として、元々のテキストを入力する画面と「message is Active」というメッセージが書かれたタブの2枚に増えました。 なので「judg.py」にて、この増えたタブに呼び出した「message.py」のレンダリング結果を載せて、「app.py」にリターンを行うという方針でよろしいでしょうか?
dodox86

2020/10/27 08:31

> なので「judg.py」にて、この増えたタブに呼び出した「message.py」のレンダリング結果を載せて、「app.py」にリターンを行うという方針でよろしいでしょうか? 方針の良し悪しを私に聞かれてもちょっと困るのですが。 あと、用語の使い方だけの話なのですが、例えば「judg.py」とは単なるファイル、あるいはPythonのモジュールを指しています。 message.pyのレンダリング結果、と書かれても、どのようにtasojiroさんが認識されているか判断しかねます。「message.py」のlogin関数のレンダリング結果を、元の呼び出し元であるはずの「app.py」中のform関数に返す、という意味なのであれば、恐らくその方針で合っているはずです。(何度も書きますが、Flaskの検証環境は持っていないので、すみませんがコメントの責任は持ちかねます)
tasojiro

2020/10/27 08:46

すみません、確かに方針を聞いても仕方ないですね。。 言いたかったのは、この考え(方針)で「app.py」から「message.py」を実行することになるか、といったことです。言い方がまずかったです。 「message.py」のlogin関数のレンダリング結果を、元の呼び出し元であるはずの「app.py」中のform関数に返す、という解釈で大丈夫です。 方針があっているとのことなので、選択肢の両方の方針でコードを探っていくことに致します。 本当にありがとうございました!
dodox86

2020/10/27 08:49

もし、ご自身で解決されたら本質問は説明と共に自己回答~解決でクローズしてください。引き続き回答を待つ為にオープンしたままとするかの判断もお任せします。
tasojiro

2020/10/27 08:51

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

2020/10/27 10:30

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

2020/10/27 11:22

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

回答1

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/30 02:40

FiroProchainezo

総合スコア2424

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tasojiro

2020/10/31 04:00

回答ありがとうございます。 実現したいこととしては、一言でいうと「webページからキーワードを入力することで、キーワードに対応したプログラムを起動する」という事です。このプログラムというのは、外部接続されたUSB内の自作プログラムに当たります。 今回は、この自作プログラムが「message.py」というwebアプリでしたが、メモ帳などの自作したプログラムがUSB内に入っていれば(webアプリではないプログラムという事です)これを起動できるようなものを考えております。 ・Flaskでのコードの分け方について。 「Blueprint」を使用して、調べながら作成し直したいと思います。ありがとうございます。 ・message.pyについて。 別サイトとして考え、サイトからサイトへ「requests」を使用して連携するという事ですね。 参考にして考え直したいと思います。 最後に、同一サイトにした方がいいとは、どういう事でしょうか?先まで別サイトとして考えるとありましたが、そもそもこの別サイトとして考えるのはやめた方がいいという事でしょうか?
tasojiro

2020/12/05 11:41

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問