Flaskメモ　＆　pythonメモ

#１.Python
#(１)クラスの概要
クラスは、class クラス名の直下にクラス変数を記載する
クラス変数はどのインスタンスでも共通で持つ変数
クラスメソッドの中にインスタンス変数を記載
クラスメソッドの第一引数はselfとするのが決まり事
インスタンス変数はインスタンス毎に利用するものであるが、self.が必要である点と、クラスメソッドを呼び出して設定しないと、アクセスしてもエラーとなる（クラス変数はそのままアクセスできる）
クラスメソッドは自動的には呼び出されない

```.py
class Car:
    #クラス変数は以下（クラス名の直下に設定する）
    #どのインスタンスでも共通で持っている変数
    #オブジェクト同士で共有できる変数
    country = "Japna"
    year = 2020

    #第一引数はselfとする
    def print_name(self):
            #インスタンス変数はメソッド内に記載
            #インスタンス変数とは、インスタンスごとに別々に利用する変数
            #インスタンス変数の前にはself.が必要
            self.name = "Prius"

#インスタンス化する
mycar = Car()

print(mycar.year)

#インスタンスメソッドが呼び出されることで、インスタンス変数が設定される
mycar.print_name()
#インスタンスメソッドが呼び出された後でないと、以下はエラーとなる
print(mycar.name)


mybus = Car()
```

#(２)クラス（コンストラクタ）
オブジェクトをインスタンス化する際に呼び出されるメソッドをコンストラクタと言う
pythonの 場合、__init__というメソッドを作成すれば、インスタンス作成時に、自動的に呼び出される


```.py
class Car:

    def __init__(self,msg):
        self.msg = msg

#インスタンス化する
#priusは、selfに代入されるのではなくmsgに入る
mycar = Car("prius")

print(mycar.msg)
```

#(３)クラス（インスタンスメソッド)

インスタンスメソッドはインスタンス化して使う
第一引数は必ずself

```.py
class Car:

    def __init__(self,msg):
        self.msg = msg

    #以下はインスタンスメソッド、第一引数は必ずself
    def print_hello(self):
        print("hellohello")

#インスタンス化する
mycar = Car("prius")

#インスタンスメソッドを設定する
mycar.print_hello()

print(mycar.msg)
```

#(４)for, while

for i in range(5):
print(i) # 0 1 2 3 4を表示

リストのループ
sample = [‘A’, ‘B’, ‘C’] for s in sample:
print(s) # A B Cを表示


count = 0
while count < 10:
print(count) count += 1



#２.Flask
#(１)動的なルーティング
動的なページとは、引数によってページの内容を変えることを言う
動的に帰る箇所は<>でくくり、型を指定する場合は例えばint:などとする
なお、Flaskのデフォルトの仕様では、パス変数を定義したら、必ず引数として定義
しなければならない

```.py
from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return "<h1>Hello World</h1>"

@app.route("/id/<int:post_num>/<post_name>")
def show_post(post_num,post_name):
    return "{}さんのIDは{}です".format(post_name,post_num)

if __name__ == "__main__":
    app.run(debug=True)
```

#(２)フィルターについて
フィルターとは、template上で値を変換できる
{{}}でくくり|（パイプ）でつなぐ
フィルターの種類にてういは[ここを参照](https://jinja.palletsprojects.com/en/2.11.x/templates/#abs)

```.html
<!DOCTYPE html>
<html lang="ja" >
  <head>
    <meta charset="utf-8">
    <title>
      MyPage
    </title>
  </head>

  <body>
      <h1>{{"hello,HOGE" |capitalize}}</h1>#最初だけ大文字にする
      <h1>{{"hello,HOGE" |lower}}</h1>#小文字に変換する
      <h1>{{"googleは
        https://google.com "|urlize(target='_blank')}}</h1>
        #文字列の中のurlを遷移できるようにする
  </body>
</html>
```

#(３)その他フィルター

```.py
from flask import Flask,render_template

app = Flask(__name__)

@app.route("/")
def index():
    user_list=["Taro","Jiro","Hanako"]

    return render_template("index.html",user_list=user_list)


if __name__ == "__main__":
    app.run(debug=True)
```

```.html
<!DOCTYPE html>
<html lang="ja" >
  <head>
    <meta charset="utf-8">
    <title>
      MyPage
    </title>
  </head>

  <body>
    <h1>最初の人は{{user_list|first}}</h1><!--最初の文字-->
    <h1>昇順にして最初の人は{{user_list|sort|first}}</h1>
　　 <!--昇順ソートして最初の文字-->
    <h1>ランダムには{{user_list|random}}</h1><!--ランダム-->
　　　　
    {% for i in user_list %}
    <li>{{i}}</li>
    {%endfor%}

　　 <!--replaceする-->
    {% for i in user_list%}
    <li>{{i |replace("Taro","太郎")}}</li>
    {%endfor%}

　　　<!--逆順にする-->
    {% for i in user_list |reverse%}
    <li>{{i}}</li>
    {%endfor%}
  </body>
</html>
```

#(４)画面遷移(url_for)
url_forを使って画面遷移させる
url_forで関数を指定すると、指定した関数に遷移することができる

```.py:test.py
from flask import Flask,render_template

app = Flask(__name__)

@app.route("/")
def index():
    return render_template("index.html")

@app.route("/home")
def home():
    return render_template("home.html")


if __name__ == "__main__":
    app.run(debug=True)
```

```.html:index.html
<!DOCTYPE html>
<html lang="ja" >
  <head>
    <meta charset="utf-8">
    <title>
      MyPage
    </title>
  </head>

  <body>
  <p>indexページ</p>
  <a href="{{url_for('home')}}">homeへの遷移</a>
  </body>
</html>
```

```.html:home.html
<!DOCTYPE html>
<html lang="ja" >
  <head>
    <meta charset="utf-8">
    <title>
      MyPage
    </title>
  </head>

  <body>
  <h1>Home</h1>
  <p>homeのページ</p>
  </body>
</html>
```

#(５)画像アップロード（url_for)
url_forを使って画像をアップロードする
staticフォルダにimageフォルダを作成し、gazoと言う画像を作成

```.html
<!DOCTYPE html>
<html lang="ja" >
  <head>
    <meta charset="utf-8">
    <title>
      MyPage
    </title>
  </head>

  <body>
  <p>indexページ</p>
  <a href="{{url_for('home')}}">homeへの遷移</a>
  <img src="{{url_for('static',filename='image/gazo.png')}}" alt="">
  </body>
</html>
```

#(６)redirect、url_forをpythonファイルで使う
redirectとurl_forをインポートする
まず、indexのページからhomeへ遷移がある
次にuserページで、Taro,45と入力すると、home2へ遷移する、その際に引数user_nameとageもdef home2にリダイレクトされる
また、userページで、Taro以外だと、indexページにリダイレクトされる

```.py
from flask import Flask,render_template,redirect,url_for

app = Flask(__name__)

@app.route("/")
def index():
    return render_template("index.html")

@app.route("/home")
def home():
    return render_template("home.html")

@app.route("/home2/<user_name>/<age>")
def home2(user_name,age):
    return render_template("home2.html",user_name=user_name,age=age)


@app.route("/user/<user_name>/<age>")
def user(user_name,age):
    if user_name in ["Taro","Jiro"]:
        return redirect(url_for("home2",user_name=user_name,age=age))
    else:
        # abort (500,"そのユーザーは無理です")
        return redirect(url_for("index"))

if __name__ == "__main__":
    app.run(debug=True)
```

```.html:index.html
<!DOCTYPE html>
<html lang="ja" >
  <head>
    <meta charset="utf-8">
    <title>
      MyPage
    </title>
  </head>

  <body>
  <p>indexページ</p>
  <a href="{{url_for('home')}}">homeへの遷移</a>
  <img src="{{url_for('static',filename='image/gazo.png')}}" alt="">
  </body>
</html>
```

```.html:home.html
<!DOCTYPE html>
<html lang="ja" >
  <head>
    <meta charset="utf-8">
    <title>
      MyPage
    </title>
  </head>

  <body>
  <h1>Home</h1>
  <p>homeのページ</p>
  </body>
</html>
```

```.html:home2.index
<!DOCTYPE html>
<html lang="ja" >
  <head>
    <meta charset="utf-8">
    <title>
      MyPage
    </title>
  </head>

  <body>
  <h1>Home</h1>
  <p>homeのページ</p>
  <p>{{user_name}}{{age}}歳</p>
  </body>
</html>
```
#(７)500エラーハンドラーをキャッチする
500エラーハンドラーは、Internal Server Error（システムエラー）
これを実装する
abortをインポートして、500エラーの際に検知して@app.errorhandler(500)で500エラーをキャッチする
error.descriptionは、abortの際の文字列を代入できる（以下のコードで言うと"そのユーザーは無理です"の箇所）

```.py:test.py
from flask import Flask,render_template,redirect,url_for,abort

app = Flask(__name__)

@app.route("/")
def index():
    return render_template("index.html")

@app.route("/home")
def home():
    return render_template("home.html")

@app.route("/home2/<user_name>/<age>")
def home2(user_name,age):
    return render_template("home2.html",user_name=user_name,age=age)


@app.route("/user/<user_name>/<age>")
def user(user_name,age):
    if user_name in ["Taro","Jiro"]:
        return redirect(url_for("home2",user_name=user_name,age=age))
    else:
        abort (500,"そのユーザーは無理です")

@app.errorhandler(500)
def system_error(error):
    #eroor.descriptionは、上記のabortメソッドの”そのユーザーは。。。"を代入できる
    error_description = error.description
    return render_template("system_error.html",error_description = error_description),500


if __name__ == "__main__":
    app.run(debug=True)
```

```.html:system_error.html
<!DOCTYPE html>
<html lang="ja" >
  <head>
    <meta charset="utf-8">
    <title>
      MyPage
    </title>
  </head>

  <body>
  <p>システムエラーが発生しました</p>
  <p>{{error_description}}</p>
  </body>
</html>
```

#(８)404エラーハンドラーをキャッチする
404エラーが発生したらキャッチして別のページに飛ばす処理をする
404を返したい場合は、 render_template("not_found.html")の後に,404をつける

```.py
from flask import Flask,render_template

app = Flask(__name__)

@app.route("/")
def index():
    return render_template("index.html")

@app.route("/home")
def home():
    return render_template("home.html")

@app.errorhandler(404)
def page_not_found(error):
    return render_template("not_found.html"),404

if __name__ == "__main__":
    app.run(debug=True)
```

```.html:not_found.html
<!DOCTYPE html>
<html lang="ja" >
  <head>
    <meta charset="utf-8">
    <title>
      not_found
    </title>
  </head>

  <body>
  <h1>ページが存在しません</h1>
  
  </body>
</html>
```

#(９)まとめ
大好きなクラロワのキャラクター画像を使って、
Mainページ、メンバーリストページ、利用規約ページを作る（利用規約は空ページ）
templatesに、以下３つのhtmlファイルを作成する
staticに、knight.png（ナイト）、mega_knight.png（メガナイト）、princess.png（プリンセス）を用意する

```.py
from flask import Flask,render_template,redirect,url_for

app = Flask(__name__)

#クラスを作成
class UserInfo:
    def __init__(self,number,name,age,picture_path):
        self.number = number
        self.name = name
        self.age = age
        self.picture_path = picture_path

#メンバーリストをクラスを用いて作成
member_list = [
    UserInfo(0,"knight",55,"image/knight.png"),
    UserInfo(1,"mega_knight",51,"image/mega_knight.png"),
    UserInfo(2,"princess",30,"image/princess.png")
]

#メインページ
@app.route("/")
def main():
    return render_template("main.html")

#メンバーの一覧ページ
@app.route("/memberlist")
def load_member_list():
    return render_template("member_list.html",member_list = member_list)

#メンバー詳細ページ
@app.route("/member/<int:member_number>")
def member_detail(member_number):
    for member in member_list:
        if member.number == member_number:
            return render_template("member_detail.html",member=member)
    return redirect(url_for("main"))

#利用規約
@app.route("/terms")
def terms_of_service():
    return render_template("terms.html")


if __name__ == "__main__":
    app.run(debug=True)
```

```.html:main.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <a href="{{url_for('main')}}">Main</a>
    <a href="{{url_for('load_member_list')}}">メンバーリスト</a>
    <a href="{{url_for('terms_of_service')}}">利用規約</a>
  </body>
</html>
```

```.html:,member_list.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <img src="{{url_for('static',filename = member.picture_path)}}">
    <li>{{member.number}}</li>
    <li>{{member.name}}</li>
    <li>{{member.age}}</li>
    <p></p>
    <a href="{{url_for('main')}}">戻る</a>
  </body>
</html>
```

```.html:member_detail
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>risuto</title>
  </head>
  <body>
    {% for member in member_list %}
    <p>
      <a href="{{url_for('member_detail',member_number = member.number)}}">
        {{member.name}}{{member.age}}
      </a>
    </p>
    {% endfor %}
    <p></p>
    <a href="{{url_for('main')}}">戻る</a>
  </body>
</html>
```

```.html:terms.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
  <p>利用規約です</p>
  <p></p>
    <a href="{{url_for('main')}}">戻る</a>
  </body>
</html>
```

ナイトのページを確認する
Mainページ→メンバーリスト→knight
![スクリーンショット 2020-09-05 15.52.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29856/705a1539-20b3-39eb-7a60-fc07c1084455.png)

#(１０)フォーム（getメソッド）
getメソッドを使ってサインアップするサイトを作る

```.py
from flask import Flask,render_template,request

app = Flask(__name__)

class UserInfo:
    def __init__(self,last_name,first_name,job,gender,message):
        self.last_name = last_name
        self.first_name = first_name
        self.job = job
        self.gender = gender
        self.message = message

@app.route("/signup")
def signup():
    return render_template("signup.html")

@app.route("/home")
def home():
    print(request.full_path)#fullpathを取得
    print(request.method)#getメソッドかpostメソッドを取得
    print(request.args)#nameに定義されている値とvalueの値を全て取得

    #クラスのインスタンスを作成する
    #request.args.getとすると、個別に取得できる
    user_info = UserInfo(
        request.args.get("last_name"),
        request.args.get("first_name"),
        request.args.get("job"),
        request.args.get("gender"),
        request.args.get("message")
    )
    return render_template("home.html",user_info = user_info)


if __name__ == "__main__":
    app.run(debug=True)
```

```.html:base.html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>Form Sample</title>
    </head>
    <body>
        {% block content %}
        {% endblock %}a
    </body>
</html>
```

```.html:signup.html
{% extends "base.html" %}
{% block content %}
<h1>サインアップページ</h1>
<form action="{{url_for('home')}}">
    <div>
        <label for="last_name">名字：</label>
        <input type="text" name="last_name">
    </div>
    <div>
        <label for="first_name">名前：</label>
        <input type="text" name="first_name">
    </div>
    <div>
        <label for="job">職業：</label>
        <select name="job">
            <option value="">選択してください</option>
            <option value="会社員">会社員</option>
            <option value="会社員">自営</option>
            <option value="会社員">公務員</option>
        </select>
    </div>
    <div>
        <input type="radio" name="gender" value="男性">男性
        <input type="radio" name="gender" value="男性">女性
    </div>
    <div>
        <textarea name="message" cols="40" rows="4"></textarea>
    </div>
    <div>
        <input type="submit" value="送信">
    </div>

</form>

{% endblock %}
```

```.html:home.html
{% extends "base.html" %}
{% block content %}
<h1>サインアップ完了</h1>
<p>{{user_info.last_name}}</p>
<p>{{user_info.first_name}}</p>
<p>{{user_info.gender}}</p>
<p>{{user_info.job}}</p>
<p>{{user_info.message}}</p>

{% endblock %}
```

#(１１)フォーム（postメソッド）
postメソッドを使う
GETリクエストの場合、フォームで送られた際に入力した値がURL欄に表示されてしまうが、POSTリクエストの場合は表示されない

```.py
from flask import Flask,render_template,request

app = Flask(__name__)

class UserInfo:
    def __init__(self,last_name,first_name,job,gender,message):
        self.last_name = last_name
        self.first_name = first_name
        self.job = job
        self.gender = gender
        self.message = message

@app.route("/signup")
def signup():
    return render_template("signup.html")

#getメソッドとの違いとして引数にGET,POSTを設定（両方取得できるようにする）
#デフォルトでは引数ない場合GETメソッドのみとなる
@app.route("/home",methods=["GET","POST"])
def home():
    print(request.full_path)#fullpathを取得
    print(request.method)#getメソッドかpostメソッドを取得
    print(request.args)#nameに定義されている値とvalueの値を全て取得

    #getメソッドとの違いとして、argsの箇所をformとする
    user_info = UserInfo(
        request.form.get("last_name"),
        request.form.get("first_name"),
        request.form.get("job"),
        request.form.get("gender"),
        request.form.get("message")
    )
    return render_template("home.html",user_info = user_info)

if __name__ == "__main__":
    app.run(debug=True)
```


```.html:base.html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>Form Sample</title>
    </head>
    <body>
        {% block content %}
        {% endblock %}a
    </body>
</html>
```

```.html:signup.html
{% extends "base.html" %}
{% block content %}
<h1>サインアップページ</h1>
<!--getメソッドとの違いとして、新たにmethod="POST"を追加-->
<form action="{{url_for('home')}}" method="POST"
    <div>
        <label for="last_name">名字：</label>
        <input type="text" name="last_name">
    </div>
    <div>
        <label for="first_name">名前：</label>
        <input type="text" name="first_name">
    </div>
    <div>
        <label for="job">職業：</label>
        <select name="job">
            <option value="">選択してください</option>
            <option value="会社員">会社員</option>
            <option value="会社員">自営</option>
            <option value="会社員">公務員</option>
        </select>
    </div>
    <div>
        <input type="radio" name="gender" value="男性">男性
        <input type="radio" name="gender" value="男性">女性
    </div>
    <div>
        <textarea name="message" cols="40" rows="4"></textarea>
    </div>
    <div>
        <input type="submit" value="送信">
    </div>

</form>

{% endblock %}
```

```.html:home.html
{% extends "base.html" %}
{% block content %}
<h1>サインアップ完了</h1>
<p>{{user_info.last_name}}</p>
<p>{{user_info.first_name}}</p>
<p>{{user_info.gender}}</p>
<p>{{user_info.job}}</p>
<p>{{user_info.message}}</p>

{% endblock %}
```

#（１２）popメソッド
pop()メソッドは引数にキーkeyを指定してその要素を削除し、削除された値valueを返す

```.py
d = {'k1': 1, 'k2': 2, 'k3': 3}

removed_value = d.pop('k1')
print(d)
# {'k2': 2, 'k3': 3}

print(removed_value)
# 1
```

第二引数を指定するとキーが存在しない場合にその値を返す。辞書オブジェクト自体は変化なし

```.py
d = {'k1': 1, 'k2': 2, 'k3': 3}

removed_value = d.pop('k4', None)
print(d)
# {'k1': 1, 'k2': 2, 'k3': 3}

print(removed_value)
# None
```

#（１３）セッション
Flaskではwebアプリとユーザを紐づけるためにセッションと呼ばれる技術を使う
セッションを使うことで、ユーザ（クライアント）を識別することができる

```.py
app.secret_key = "●●●●●" # 暗号化用の鍵
@app.route("/login")
def login():
   if "userid" not in session: # ログインを確認
       user_id = request.form["user_id"]
       session["userid"] = user_id
   return redirect(url_for("logined"))
```

#（１４）セッション（その他）
違う例を以下の通り

```.py
from flask import Flask, session
app = Flask(__name__)
app.secret_key = '●●●●●●'

@app.route('/')
def index():
  return 'hello'

if __name__ == '__main__':
    app.run(debug=True)
```

from flask import Flask, sessionで明示的にsessionをimportしている点と、app.secret_keyが必要な点、これがないとエラーになる。

```.py
session['name'] = '太郎'　#書き込み
name = session.get('name') #読み込み
#session['name']でも取得できるが、値がなかったときにエラーになるのでsession.get()の方が値がない場合はNoneが返る
session.pop('name', None) #削除
```
ちなみに、secretkeyは、ランダムが望ましい
Flaskチュートリアルより
https://study-flask.readthedocs.io/ja/latest/02.html

```
>>> import os
>>> os.urandom(24)
'\xfd{H\flash: xe5<\x95\xf9\xe3\x96.5\xd1\x01O<!\xd5\xa2\xa0\x9fR"\xa1\xa8
```

#（１５）rediredtとrender_templateの違い

例えば以下のコード

```.py
@app.route('/')
def hello():
    return redirect("http://www.example.com")
```
これは、localhost:5000/にアクセスしたときに、URLがhttp://www.example.comに遷移される

```.py
@app.route("/index")
def index():
    message = 'sample_string'
    return render_template('index.html', message=message)
```
これは、localhost:5000/index にGETリクエストを送った時に、templates/index.htmlをVIEWに返すという処理
templateのhtmlをhoge.htmlだったら、普通にlocalhost:5000/indexにアクセスしても表示されるViewはhoge.htmlになる

#（１６）JavaScriptと、css読み込み

```.py
<!-- JavaScript読込 -->
<script type="text/javascript" src="{{ url_for('static', filename='js/sample1.js') }}">

<!-- #css読込 -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/sample1.css') }}">

```