ぴよ丸水産

週末ファゴッティストによる技術ブログ

【Python】プログラミング初心者がFlaskでPythonをかじってみた話 コーディング編

カリカリ書いてた時期から1か月経ってしまいました。
環境構築編 の続きです。
あ、ちなみに最近、格安SIMに乗り換えました!
参考程度にソースコードを一番下に張り付けておこうと思いますが、
プログラムを書いたのは、ほぼ初めてなので、その辺りはご容赦願いますm( )m

学び①:辞書型の使い方

下記のように、料金プランの持つ値を辞書型の変数で定義しました。

plan_pattern_a = {
    "plan_s":{
        "charge":1980, "data":2.0, "freetalk":60
    },
    "plan_m":{
        "charge":2980, "data":6.0, "freetalk":120
    },
    "plan_l":{
        "charge":4980, "data":14.0, "freetalk":180
    }
}

定義した変数をどう使ったかは、下記の通り。
選んだプランに応じてifで分岐させました。
変数名['key']でとってこれます。
階層の場合は['key']['key']すればOKです。

    sammary_a = Sammary()
    sammary_a.plan = plan
    sammary_a.month = (int)(request.form['month'])
    if sammary_a.plan == "プランS":
        month_charge = plan_pattern_a["plan_s"]["charge"]
        freetalktime = plan_pattern_a["plan_s"]["freetalk"]
    elif sammary_a.plan == "プランM":
        month_charge = plan_pattern_a["plan_m"]["charge"]
        freetalktime = plan_pattern_a["plan_m"]["freetalk"]
    elif sammary_a.plan == "プランL":
        month_charge = plan_pattern_a["plan_l"]["charge"]
        freetalktime = plan_pattern_a["plan_l"]["freetalk"]
        if 'attention' in locals():
            sammary_a.comment.append("※比較対象プランで提供できる最大のデータ容量は21GB※※")
        else:
            pass

ちなみに、しれっとSammaryクラスが登場していますが、
彼はこんなクラスです。

class Sammary:
    def __init__(self):
        self.plan = ""
        self.month = 0
        self.total = 0
        self.comment = []

Webアプリユーザが入力した値(プランや使用期間)を各携帯会社の計算ロジックに投入して、
それぞれの合計金額や、注意事項を出力するためには、
それらの情報をひとまとめにして、オブジェクトとして扱うのがよさげかな、
と思い、クラスを作ってみました。

学び②:HTMLとPythonのデータの受け渡し

HTML(ユーザの入力)→Python

HTML入力部分(templates/index.html)

<form action="/result" method="post">
  <p>
    <input type="radio" name="plan_base" value="tanmatsu" checked>スマホとセットで契約<br>
    <input type="radio" name="plan_base" value="simonly">SIMカードのみで契約<br>
    <input type="number" name="data_need" value=3>GB程度使用する<br>
    <input type="number" name="month" class="testbox01" value=1>ヶ月使用した場合<br>
    <button type="submit" class="btn btn-default">合計料金を表示</button>
  </p>

ちなみにUIはこんな感じ

f:id:blue-38:20190829201340p:plain
入力画面

Pythonでどう使うかというと、
以下、data_need(ユーザが普段使用する月々のデータ容量)の例です。

# 使用データ容量からプランを判定
    if (int)(request.form['data_need']) <= 3:
        plan = "プランS"
    elif (int)(request.form['data_need']) > 3 and (int)(request.form['data_need']) <= 9:
        plan = "プランM"
    elif (int)(request.form['data_need']) > 9:
        plan = "プランL"
        if (int)(request.form['data_need']) > 21:
            attention = True

数値として処理に使う場合は、 上記のように(int)(…)で変換しました。

Python→HTML

pythonからHTMLに渡している現場はこちら。

    # index.html をレンダリングする
        return render_template('index.html',
                                plan_pattern_a=plan_pattern_a, sammary_a=sammary_a,sammary_b=sammary_b, title=title)

料金情報(plan_pattern_a)→HTML側のplan_pattern_a 合計情報(sammary_a,sammary_b)→HTML側のsammary_a,sammary_b

上記のように渡しています。
対するHTML側はどうなっているかというと。

(templates/index.html)

  <div class= "frame02">
    <p>★{{ sammary_uq.plan }}を{{ sammary_uq.month }}ヶ月使用した場合<br></p>
    {% for comment in sammary_uq.comment %}
      <p>※{{ comment }}<br></p>
    {% endfor %}
  </div>
  <div class="frame01">
    <p>
      ¥{{ sammary_uq.total }}<br>
    </p>
  </div>

UIはこうなります。
可変の部分はpythonで渡したオブジェクトから、
変数を引っぱってきています。

f:id:blue-38:20190829201516p:plain
出力画面

まとめ

何か言語を習得したければ、とにかくコーディングしてみることが大事。
Flaskは作ったものが、形になって見えるし、
これからいっちょPythonやろうかなって人にはFlaskはうってつけかと思います。

この独学のおかげで今、
業務でpythonスクリプト書いたりしてます。
(まだまだ格好悪いコードですが。。)

参考

pythonのコードです。
作った時は携帯会社わかるようにしてましたが、
ブログに載せるとなると、
情報の確実性が怪しいので、A社とかB社にしました。
ただ、割引の名前は何か聞いたことあるかもなので、
推測可能です。

from flask import Flask, render_template, request, redirect, url_for
import numpy as np

# 自身の名称を app という名前でインスタンス化する
app = Flask(__name__)

#A社・B社料金
#charge_a = {"plan_s":1980, "plan_m":2980, "plan_l":4980}

# データ容量定義
#base_data_a = {"plan_s":2.0, "plan_m:":6.0, "plan_l":14.0}

plan_pattern_a = {
    "plan_s":{
        "charge":1980, "data":2.0, "freetalk":60
    },
    "plan_m":{
        "charge":2980, "data":6.0, "freetalk":120
    },
    "plan_l":{
        "charge":4980, "data":14.0, "freetalk":180
    }
}

class Sammary:
    def __init__(self):
        self.plan = ""
        self.month = 0
        self.total = 0
        self.comment = []


# ここからウェブアプリケーション用のルーティングを記述
# index にアクセスしたときの処理
@app.route('/')
def index():
    title = "携帯料金シミュレータ"
    # index.html をレンダリングする
    return render_template('index.html',
                            plan_pattern_a=plan_pattern_a, title=title)

# /result にアクセスしたときの処理
@app.route('/result', methods=['GET', 'POST'])
def post():
    title = "携帯料金シミュレータ"
# 使用データ容量からプランを判定
    if (int)(request.form['data_need']) <= 3:
        plan = "プランS"
    elif (int)(request.form['data_need']) > 3 and (int)(request.form['data_need']) <= 9:
        plan = "プランM"
    elif (int)(request.form['data_need']) > 9:
        plan = "プランL"
        if (int)(request.form['data_need']) > 21:
            attention = True

### A モバイル
    sammary_a = Sammary()
    sammary_a.plan = plan
    sammary_a.month = (int)(request.form['month'])
    if sammary_a.plan == "プランS":
        month_charge = plan_pattern_a["plan_s"]["charge"]
        freetalktime = plan_pattern_a["plan_s"]["freetalk"]
    elif sammary_a.plan == "プランM":
        month_charge = plan_pattern_a["plan_m"]["charge"]
        freetalktime = plan_pattern_a["plan_m"]["freetalk"]
    elif sammary_a.plan == "プランL":
        month_charge = plan_pattern_a["plan_l"]["charge"]
        freetalktime = plan_pattern_a["plan_l"]["freetalk"]
        if 'attention' in locals():
            sammary_a.comment.append("※比較対象プランで提供できる最大のデータ容量は21GB※※")
        else:
            pass
# 通話プラン
    if request.form['talking'] == "osyaberi":
        sammary_a.comment.append("1回5分以内の国内通話無料")
    elif request.form['talking'] == "pittari":
        sammary_a.comment.append(f"無料通話{freetalktime}分/月")
# 家族割引の適用
    if request.form['discount_a'] == "family":
        month_charge = month_charge - 500
        sammary_a.comment.append("家族割で基本料金から500円引き")
    else:
        pass
# ギガMAX月割の適用
    if request.form['discount_a'] == "wifi":
        month_charge = month_charge -300
        sammary_a.comment.append("AWiMAXとセットで300円引き")
    else:
        pass
# 使用期間によって処理を分岐
    if request.method == 'POST':
        if sammary_a.month < 13:
            sammary_a.total = month_charge * sammary_a.month
        elif sammary_a.month >= 13:
            sammary_a.total = month_charge * 12
            month_charge = month_charge +1000
            sammary_a.total = sammary_a.total + (month_charge * (sammary_a.month-12))
            if request.form['deta_increase_a'] == 'on' and sammary_a.month > 25:
                sammary_a.total = sammary_a.total + (500 * (sammary_a.month-24))
                sammary_a.comment.append("データ容量は3年目以降も変わらない")
                sammary_a.comment.append("3年目から基本料500円増加")
            elif request.form['deta_increase_a'] == 'off' and sammary_a.month > 25:
                sammary_a.comment.append("3年目からデータ容量減少")
                freetalktime = freetalktime / 2
                sammary_a.comment.append(f"3年目からは無料通話{freetalktime}分/月")
# 金額が負の値にならないようにする(使用期間0ヶ月で割引にチェックを入れた場合など)
        if sammary_a.total < 0:
            sammary_a.total = 0
        else:
            pass
# 3桁ごとにカンマを入れる(整形)        
        sammary_a.total = "{:,d}".format(sammary_a.total)

### B モバイル
    sammary_b = Sammary()
    sammary_b.plan = plan
    sammary_b.month = (int)(request.form['month'])
    sammary_b.comment.append("1回10分以内の国内通話無料")
    if sammary_b.plan == "プランS":
        month_charge = plan_pattern_a["plan_s"]["charge"]
        discount_plice = 500
    elif sammary_b.plan == "プランM":
        month_charge = plan_pattern_a["plan_m"]["charge"]
        discount_plice = 700
    elif sammary_b.plan == "プランL":
        month_charge = plan_pattern_a["plan_l"]["charge"]
        discount_plice = 1000
# おうち割 光セット
    if request.form['discount_b'] == "family":
        month_charge = month_charge - discount_plice
        sammary_b.comment.append(f"インターネットとセットで{discount_plice}円引き")
# 家族割引の適用
    elif request.form['discount_b'] == "wifi":
        month_charge = month_charge - 500
        sammary_b.comment.append("家族割で基本料金から500円引き")
    else:
        pass
# 使用期間によって処理を分岐
    if request.method == 'POST':
        if sammary_b.month < 13:
            sammary_b.total = month_charge * sammary_b.month
        elif sammary_b.month >= 13 and sammary_b.month < 25:
            sammary_b.total = month_charge * 12
            month_charge = month_charge +1000
            sammary_b.total = sammary_b.total + (month_charge * (sammary_b.month-12))
            if request.form['deta_increase_b'] == 'on' and sammary_b.month >= 25:
                sammary_b.total = sammary_b.total + (500 * (sammary_b.month-24))
                sammary_b.comment.append("データ容量は3年目以降も変わらない")
                sammary_b.comment.append("3年目から基本料500円増加")
            elif request.form['deta_increase_b'] == 'off' and sammary_b.month >= 25:
                sammary_b.comment.append("3年目からデータ容量減少")
# 金額が負の値にならないようにする(使用期間0ヶ月で割引にチェックを入れた場合など)
        if sammary_b.total < 0:
            sammary_b.total = 0
        else:
            pass

# 3桁ごとにカンマを入れる(整形)         
        sammary_b.total = "{:,d}".format(sammary_b.total)

    # index.html をレンダリングする
        return render_template('index.html',
                                plan_pattern_a=plan_pattern_a, sammary_a=sammary_a,sammary_b=sammary_b, title=title)
    else:
        # エラーなどでリダイレクトしたい場合はこんな感じで        
        return redirect(url_for('index'))

if __name__ == '__main__':
    app.debug = True # デバッグモード有効化
    app.run() # どこからでもアクセス可能に