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

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

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

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

Python

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

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

Q&A

解決済

1回答

768閲覧

楽天API を使ってwebアプリをflaskで実装したいです

toru122

総合スコア3

Flask

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

Python

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

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

0グッド

1クリップ

投稿2023/02/20 08:01

編集2023/02/21 19:18

実現したいこと

楽天API を使ってwebアプリをpythonのflaskで実装したいです

楽天レシピカテゴリ別ランキングAPIというものを使いウェブアプリを作ろうとしています。ボタンを押すとランダムに今日のご飯メニューを提示してくれるといったものを想像しています。(今回は豚肉料理に絞りたいです。)
flaskでできるかなと思い考えて行っていたのですが、ボタンを押した後画面を転移させ、apiをたたき画面に反映させるのかがわからずにいます。htmlのformタグを使いpythonのファイルと紐づけさせたらいいのではと思っているのですが、書き方がわからず困っています。ちがうのでしょうか。randomモジュールもどこにどのように書けばよいのかわかりません。どなたか教えていただけないでしょうか。

2・21 編集後

該当のソースコード views.py

from flask import Flask, request, render_template import main # アプリ生成 app = Flask(__name__) # ルーティング @app.route("/") def form(): return render_template('form.html') @app.route("/summon", methods=['GET', 'POST']) def summon(): if request.method == 'POST': api = main.api() return render_template('summon.html', data=api) if __name__ == "__main__": app.run(debug=True)

該当のソースコード main.py

import requests # urlの作成 def api(): REQUESTS_URL = 'https://app.rakuten.co.jp/services/api/Recipe/CategoryRanking/20170426' APP_ID = '' # 簡単豚肉料理に絞った範囲 item_parameters = { 'applicationId': APP_ID, 'format':'json', 'formatVersion': 2, 'categoryId': '36-494', 'elements': 'recipeTitle,recipeUrl,mediumImageUrl,recipeIndication' } # jsonデータの取得 res = requests.get(REQUESTS_URL, item_parameters) result = res.json() return result

該当のソースコード form.html

<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title></title> </head> <body> <h1></h1> <br> <form action="/summon.html" method='POST'> <h3>押してください</h3> <button type="submit">開始</button>

該当のソースコード summon.html

<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h2>今日の豚肉料理は</h2> {{ data }} </body> </html>

になります。
現状では
ボタンをクリックするとsummon.htmlに遷移したのち
Not Found
The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.と表示されます。

views.py に main.py をimportするとこのように出ます。
importしなければ通常に遷移します。

初歩的な部分で詰まっているのかもしれませんが、ご指摘いただけると幸いです。
よろしくお願いいたします。

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

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

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

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

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

meg_

2023/02/20 08:36

楽天APIの使い方は分かっている、という前提で良いでしょうか?
toru122

2023/02/20 08:41

はい!コマンドプロンプトにほしかった情報が出力できましたので扱い方はなんとなく理解したつもりです。 出力したものをWEBアプリに反映させたく質問させていただきました。
meg_

2023/02/20 08:48

(現状で画面遷移自体はちゃんと出来ている前提で)def summon()の中で楽天APIにアクセスしてその結果を返せば良さそうですが。(詳しくは見てないので違うかもしれません)
toru122

2023/02/20 09:46

def summon(): if request.method == 'POST': return render_template('summon.html') の状態では'summon.htmlが返ってきます。 APIにアクセスし結果を返すために import mainとして、 def summon(): if request.method == 'POST': return main とすると無効な値なので返せませんと出ました。APIの返し方がわからないのですがお分かりにならないでしょうか。初心者で知識がなく何日もはまってしまっています。。
meg_

2023/02/20 10:04 編集

summon.htmlに対して楽天APIの結果を渡せば良いかと思います。 return render_template('summon.html', aaa=bbb)のような感じで。具体的な書き方は受け取り側の実装に依るかと思います。 > APIの返し方がわからないのですがお分かりにならないでしょうか。初心者で知識がなく何日もはまってしまっています。。 APIの返し方ではありませんが、値の渡し方等はドキュメント(https://msiz07-flask-docs-ja.readthedocs.io/ja/latest/quickstart.html)を一通り読まれると良いかと思います。
toru122

2023/02/20 10:25

ご丁寧にありがとうございます!ドキュメント見てやってみます!
guest

回答1

0

ベストアンサー

何日もはまっている、ということなので、考え方を記載します。

考え方を記載する前に指摘

質問に記載されている base.html ですが、使用されていません。
何かに使用しているつもりでしょうか?
baseなので、もしかしたらこれを全部に適応したいのかもしれません。
その場合、以下のページを参照していただき、記述方法を確認ください。

テンプレート

base.htmlは、このページの「ベースレイアウト」のものと思います。
form.htmlとsummon.htmlは「登録」や「ログイン」の記述をすべきページです。
つまり、form.htmlsummon.html{% extends 'base.html' %}から始まる必要があります。
このページにある、base.html{% block title %}{% block header %}{% block content %}があるので、登録ログイン側でも、定義されている部分の内、必要な部分を記載しています。

質問にあるbase.htmlの場合、{% block content %}しか定義されていないので、content以外は置き換えられない事に注意してください。
また、form.htmlでは{% block content %}を書いていますが、{% extends 'base.html' %}が無いので、何を置き換えるか定義されていないことに注意してください。

次に、main.pyの方ですが、インデントが正しくありません。
以下の部分です。
インデントは正しく入力しましょう。

py

1# jsonデータの取得 2 res = requests.get(REQUESTS_URL, item_parameters) 3 result = res.json()

考え方

処理の流れ

  1. /にGETでアクセス。
    form.htmlが表示される。
  2. <button type="submit">開始</button>を押す。
    action="/summon.html"なので、/summon.htmlに、POSTメソッドで移動。
    formの入力値は、特に何も無い。
  3. def summon():が呼び出される。

現状は、1,2は無くても良いので、3の作り込みをすれば良いと思います。

つまり以下の部分です。

py

1@app.route("/summon.html", methods=['GET', 'POST']) 2def summon(): 3 if request.method == 'POST': 4 return render_template('summon.html')

POSTで来るのは決まっているので、if request.method == 'POST':の中だけ変えればOKです。

例えば、

py

1 # main.pyの処理を全部持ってくる。(importは上に書く) 2 result = res.json() 3 return render_template('summon.html', data=result) 4

resultの中身はどうなっているのか分かりませんが、summon.htmlを以下の様にすると、dataの中身(dataにはresultを入れているので、resultの中身)を表示可能です。

html

1<!DOCTYPE html> 2<html lang="ja"> 3<head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <title>Document</title> 8</head> 9<body> 10 <h2>今日の豚肉料理は</h2> 11 {{ data }} 12</body> 13</html>

あと、関係無いですが、@app.routeの第一引数に拡張子は不要です。
例: @app.route('summon', methods=['GET', 'POST'])

formのactionにこのsummonを指定したい場合は、action="{{ url_for('summon') }}"の様にすると、パスが変わっても変更不要になります。
ちなみに、url_for()に指定するのはパスではなく、関数名(def summon():)の方なので気をつけてください。

投稿2023/02/20 11:06

FiroProchainezo

総合スコア2385

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

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

toru122

2023/02/21 04:46

返信が遅くなり申し訳ありません。ご丁寧にありがとうございます! ご指摘の通り、base.htmlをベースにして作ろう!と思っていたのですが{% extends 'base.html' %}などを書き忘れていました。考えてみたらjinjaテンプレートを使わないほうがよかったなと個人的には思います。インデントのご指摘もありがとうございます。いろいろいじっていたらずれてしまっていました。。 回答の中で ``` python # main.pyの処理を全部持ってくる。(importは上に書く) result = res.json() return render_template('summon.html', data=result) ``` とアドバイスいただきましたが、import main とするだけでは result = res.json()ってなに?という判定になります。 そこでviews.py の中でimport main、 main.pyの内容全体をdef api():と定義し views.py ``` python @app.route("/summon", methods=['GET', 'POST']) def summon(): if request.method == 'POST': main.api result = res.json() return render_template('summon.html', data=result) ``` としてみたのですがうまくいきません。どうかけばmain.pyを呼び出せるのかご教授いただけないでしょうか。
FiroProchainezo

2023/02/21 04:55

一番簡単なのは、関数化してそれを呼び出す事だと思います。 Flask側にリクエスト来る度に、API叩いてたら楽天側で止められるかもしれませんが、今は開発段階なので、それは後で解決しましょう。 関数については、ググったら以下が見つかりました。 https://www.python.jp/train/function/index.html https://www.tohoho-web.com/python/function.html 公式はこれかな? https://docs.python.org/3/reference/compound_stmts.html#function-definitions
toru122

2023/02/21 06:38

何度もすみません。どうしてもわからなくて。。 おっしゃる通り、main.py をdef api():と関数化して import したつもりなのですがどこが間違っているのでしょうか。 main.py ``` import requests # urlの作成 def api(): REQUESTS_URL = 'https://app.rakuten.co.jp/services/api/Recipe/CategoryRanking/20170426' APP_ID = '' # 簡単豚肉料理に絞った範囲 item_parameters = { 'applicationId': APP_ID, 'format':'json', 'formatVersion': 2, 'categoryId': '36-494', 'elements': 'recipeTitle,recipeUrl,mediumImageUrl,recipeIndication' } # jsonデータの取得 res = requests.get(REQUESTS_URL, item_parameters) result = res.json() return result ``` この書き方ではおかしいですか?前提としてprint(api())とすればしっかりほしい値が返ってきます。 views.py ``` from flask import Flask, request, render_template import main # アプリ生成 app = Flask(__name__) # ルーティング @app.route("/") def form(): return render_template('form.html') @app.route("/summon", methods=['GET', 'POST']) def summon(): if request.method == 'POST': api = main.api() return render_template('summon.html', data=api) if __name__ == "__main__": app.run(debug=True) ``` になります。申し訳ないのですが教えていただけますでしょうか。
FiroProchainezo

2023/02/21 06:49

すみません、コメントはインデントが保持されないので、コードを書くのに不向きです。 (数行なら読めないことも無いですが、長くなると、読むのが厳しくなります。 特にPythonはインデントが必須ですが、コメント欄ではインデントが消えます。) 回答に対応してコードを書き換えたと言う場合は、質問を修正いただき、「質問のコードを○○のような意図で書き換えた、確認して欲しい」みたいなコメントを書いていただけると、回答しやすいです。 また、追記の質問ですが「main.py をdef api():と関数化して import したつもりなのですがどこが間違っているのでしょうか。」とありますが、間違っていると判断した理由がわかりません。 なんらかのエラーが出ているのでしょうか? それとも、何も表示できないなどの問題があるのでしょうか? summon.htmlには{{data}}を追加しましたか? それとも、画面遷移できない等の他の問題でしょうか?
toru122

2023/02/21 07:03

そうですよね!確かに読みにくいですね!失礼しました。 わかりました。質問を修正します。 なぜ間違っているか判断したのかというと、summon.html に遷移したとき、 Not Found The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. と出るからです。main.py をimportしないときは正しくsummon.htmlに書いてあるテキストが表示されます。 summon.htmlには{{data}}を追加しました。
FiroProchainezo

2023/02/21 08:39

もう書き換わっている気がするので、現状のコードで回答を書きます。 エンドポイント(URL, パス)を書き換えたら、HTMLのForm側のaction先も変える必要があります。 ``` @app.route("/summon", methods=['GET', 'POST']) ``` 回答の一番下に書いた通り、url_forを使うと便利です。 ``` <form action="{{ url_for('summon') }}" method='POST'> ``` url_forを使わない場合はaction="/summon"ですね。 あと、今回は関係無いみたいですが、main.pyとか def api()とかを使うのはお勧めしません。 main.pyはなんか最初に作ったのをそのまま使い回している感じで、何をするのか不明ですし、apiは何のapiなのか分かりません。 (main.pyがメインなら問題無いです。 今回はFlask側のviews.pyがメインファイルのはずで、main.pyはviews.pyから読み込まれるだけものなので指摘しています。) 日本語のローマ字表記とかでも良いので、別のにした方があとあと便利だと思います。 例えば、ファイル名をapi_manager.pyとか適当に変えて、api()側は、get_meat_dish()とか、なんとなく何をやっているのか分かるようにしましょう。 関数名を付ける際は、PEP8に従って、スネークケース(全部小文字で、単語をアンダーバーつなぎ)を使う癖を付けましょう。 また、Flaskのファイルは慣例的にapp.pyを使われることが多いです。 app.pyが前提で動くアプリ(gunicornとか,flask runの場合はapp.pyかwsgi.py)もあるので、app.pyとした方が便利かもしれません。
toru122

2023/02/21 09:23

ご指摘ありがとうございます!! おっしゃる通り <form action="{{ url_for('summon') }}" method='POST'> に変更したところ、APIの値をsummon.htmlと一緒に返すことができました!!!! あとは見やすいように表示させるところ、ランダムに値を返すところはまた自力で頑張りたいと思います! ファイル名、関数名の決め方も非常に参考になりました。 一人独学のため、教えてくださる人が周りにいなかったですが助けていただき感謝しています。 ご丁寧に、本当にありがとうございました!
FiroProchainezo

2023/02/21 10:18

解決したようで良かったです。 疑問点等がまた出てきたら質問ください。 Flaskの質問はできるだけ回答するようにしています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.53%

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

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

質問する

関連した質問