Computed propertyについて

はじめに

こういう記述がでてきて面食らったのでメモ

struct Sport {
    var name: String
    var isOlympicSport: Bool

    var olympicStatus: String {
        if isOlympicSport {
            return "\(name) is an Olympic sport"
        } else {
            return "\(name) is not an Olympic sport"
        }
    }
}

var olympicStatus のところはComputed propertyというらしい。

説明

var hoge{
    return 〜
}

という記法があって、これはcomputedプロパティという。 computedプロパティは決まった値を持っておらず、他のプロパティの値を元に処理を行い結果を返す挙動をする。

参考

www.hackingwithswift.com

wtformsで簡単な入力フォームを作る

はじめに

wtformsを使って簡単な入力フォームを作る方法をメモしておく。

フォルダ構成

FORM_TEST
  ├─templates
  │  ├─regist_user.html
  │  └─show_user.html
  └─app.py

コード

app.py

from flask import Flask, render_template, request, session
from wtforms import Form
from wtforms import StringField, IntegerField, SubmitField

app = Flask(__name__)
app.config['SECRET_KEY'] = 'mykey'

class UserForm(Form):
    name = StringField('名前:')
    age = IntegerField('年齢:')
    submit = SubmitField('送信')

@app.route('/', methods=['GET', 'POST'])
def index():
    form = UserForm(request.form)

    # 登録フォームを表示
    if(request.method == "GET"):
        return render_template('regist_user.html', form=form)

    # 登録完了を表示
    elif(request.method == "POST"):
        session['name'] = form.name.data
        session['age'] = form.age.data
        return render_template('show_user.html')

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

regist_user.html

<!DOCTYPE html>
<html lang="'ja">
    <head>
        <meta charset="utf-8">
        <title>regist_user</title>
    </head>
    <body>
        <form method="POST">
            {{ form.csrf_token }}
            {{ form.name.label }}{{ form.name() }}  <br>
            {{ form.age.label }}{{ form.age() }}    <br>
            {{ form.submit }}
        </form>
    </body>
</html>

show_user

<!DOCTYPE html>
<html lang="'ja">
    <head>
        <meta charset="utf-8">
        <title>show_user</title>
    </head>
    <body>
        <h1>Thank you for regist</h1>
        <ul>
            <li>名前: {{session['name']}}</li>
            <li>年齢: {{session['age']}}</li>
        </ul>
    </body>
</html>

flask_sqlalchemyでトランザクション処理

はじめに

 データベースにデータを追加したり削除したりといった操作をする場合、たいていは複数の操作をまとめて実行することが多い。

 例えば、あるネットショップのデータベースが「商品テーブル」「注文テーブル」「注文詳細テーブル」で構成されているとする。ある商品の注文が入ったら「注文詳細テーブル」に注文された商品や数量などを保存すると同時に、「商品テーブル」の在庫数を減らさなければならない。これがどれかの処理でエラーが発生し、途中で止まってしまったらどうなるか。注文は入ったけど在庫数が減らないなんていう事態が発生してしまう。これは絶対に避けたい。

 だからデータベースの処理は「すべての正常に変更し"確定"」か、「一個でもエラーが発生したらすべての変更を"破棄"」のどっちかでなけれなならない。このような処理をトランザクション処理という。

実装方法

流れ

トランザクション処理は下記により実装する。

with db.session.begin(subtransactions=True):
    # データベースへの分割不可な一連処理
db.session.commit()

以前の記事を参考にデータベースを作成し、操作するプログラムを実装する。

progmemo.hatenablog.jp

階層構造

MODEL_EXAM
  ├─app.py
  └─model_exam.sqlite

コード

# app.py
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
basedir = os.path.abspath(os.path.dirname(__name__))
app.config['SECRET_KEY'] = 'mysecretkey'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'model_exam.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)

class Members(db.Model):
    __tablename__ = 'members'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.Text)
    age = db.Column(db.Integer)
    comment = db.Column(db.Text)

    def __init__(self, name, age, comment):
        self.name = name
        self.age = age
        self.comment = comment
db.create_all()  # テーブルの作成

# トランザクション処理
with db.session.begin(subtransactions=True):
    # データベースへの分割不可な一連処理
    new_member = Members("john", 29, "aaaabbbb")
    db.session.add(new_member)

db.session.commit()

参考にしたサイト

https://wa3.i-3-i.info/word16325.html

トランザクション管理とは?

flask_bcryptでパスワードを暗号化する方法

はじめに

flaskでログイン画面を作成する際、パスワードを入力して正しければログインを認証し、間違っていれば弾く必要がある。パスワードは暗号化してデータベースに登録する。そこで使用するのが暗号化関数のbcryptである。

使い方

暗号化メソッドgenerate_password_hash()と確認メソッドcheck_passwoed_hash()は下記のように使う。

from flask_bcrypt import Bcrypt

bcrypt = Bcrypt()  # Bcryptオブジェクトの作成

pd = 'test1234'    # パスワード
hashed_pd = bcrypt.generate_password_hash(password=pd)  # 暗号化

val = input('パスワードを入力してください: ')
check = bcrypt.check_password_hash(hashed_pd, val)  # 確認。第一引数が暗号化された値で第二引数が平文。

if(check):
    print("正解")
else:
    print("不正解")

参考にしたサイト

Flaskで作るSNS Flask(Blueprint,bcrypt)編 - Qiita

Blueprintの使い方メモ

はじめに

flaskのBlueprintについて忘れないうちにメモ

Blueprintとは

BlueprintとはFlaskで使われるモジュールであり、アプリケーションの機能を分割して実装するためのものである。

Blueprintを使わない場合

例えば以下のようなプログラムがあったとする。Blueprintを使わない場合、すべてのHTTPリクエストを1つのviews.pyで受ける必要がある。プログラムの規模が大きくなってくるとコードが長くなり保守性が悪い。

階層構造

test
  └─views.py

コード

func1とfunc2がそれぞれ機能の塊であるとみなす。

# views.py
from flask import Flask

app = Flask(__name__)

@app.route('/func1/a')
def func1_a():
    return 'func1_a'

@app.route('/func1/b')
def func1_b():
    return 'func1_b'

@app.route('/func2/a')
def func2_a():
    return 'func2_a'

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

実行結果

ブラウザで
http://127.0.0.1:5000/func1/aにアクセスすると func1_aが表示される
http://127.0.0.1:5000/func1/bにアクセスすると func1_bが表示される
http://127.0.0.1:5000/func2/aにアクセスすると func2_aが表示される

Blueprintを使用した場合

上でも書いた通り、全部1つのviews.pyに記述すると保守性が悪いため、分割して書きたい。こういうときに利用するのがBlueprintである。

階層構造

func1フォルダとfunc2フォルダを作成し、その中にそれぞれviews.pyを作成する。func1の機能はfunc1/views.pyに記述し、func2の機能はfunc2/views.pyに記述していく。さらに実行用として、app.pyを作成する。

test
  ├─func1
  │  └─views.py
  ├─func2
  │  └─views.py
  └─app.py

コード

func1/views.py
# func1/views.py
from flask import Blueprint

# func1のBluePrint
func1 = Blueprint(
    'func1',    # Blueprintの名前
    __name__,    # __name__とする
    url_prefix='/func1'    # URLの最初の部分
)

@func1.route('/a')    # /func1/a
def func1_a():
    return 'func1_a'

@func1.route('/b')       # /func1/b
def func1_b():
    return 'func1_b'
func2/views.py
# func2/views.py
from flask import Blueprint

# func2のBlueprint
func2 = Blueprint('func2', __name__, url_prefix='/func2')

@func2.route('/a')
def func2_a():
    return 'func2_a'
app.py
# app.py

from flask import Flask
from func1.views import func1
from func2.views import func2

app = Flask(__name__)

# blueprintをアプリケーションに登録
app.register_blueprint(func1)
app.register_blueprint(func2)

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

実行結果

app.pyを実行すると、上記Blueprintを使わない場合と同じ結果となる。

参考にしたサイト

いまさらながら Flask についてまとめる 〜Blueprint〜 - 適当おじさんの適当ブログ

flask_sqlalchemyでデータベースを作る方法

はじめに

flask_sqlalchemyを使ってsqliteデータベースを作成する方法をまとめる

階層構造

MODELS2
  └─model.py

流れ

  1. SQLAlchemyの設定
    1. Flaskオブジェクトの定義
    2. データベースの名称、場所の指定
    3. その他SQLAlchemyの設定
  2. SQLAlchemyオブジェクトを作成
  3. モデルクラスを作成
    1. テーブル名の定義
    2. カラムの定義
  4. テーブルの作成
    1. create_all()関数でデータベースに新しいテーブルを作成する

コード

import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

# SQLAlchemyの設定
base_dir = os.path.dirname(__file__)
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(base_dir, 'DataBase1.sqlite')

# SQLAlchemyオブジェクトを作成
db = SQLAlchemy(app)

# モデルクラスを作成
class Person(db.Model):
    __tablename__ = 'persons'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(20))
    phone_number = db.Column(db.String(13))
    age = db.Column(db.Integer)
    create_at = db.Column(db.DateTime)
    update_at = db.Column(db.DateTime)

    def __init__(self, name, phone_number, age, create_at, update_at):
        self.name = name
        self.phone_number = phone_number
        self.age = age
        self.create_at = create_at
        self.update_at = update_at

# テーブルの作成 
db.create_all()

実行結果

実行するとmodel.pyと同じ階層に「DataBase1.sqlite」が作成される。

test
  ├─model.py
  └─Database1.sqlite

既に同名のテーブルがある場合、db.create_all()しても新しくテーブルは作成されない。

他モジュールに定義したクラスをインポートする方法

はじめに

クラスを別ファイル化する方法を毎回忘れてしまうのでメモ。module1に定義したHumanクラスをmodule2で使用する方法。

階層構造

test
  ├─module1.py
  └─module2.py

コード

module1.pyの記述

class Human:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return "名前:" + str(self.name) + " 年齢:" + str(self.age)

module2の記述

from module1 import Human

hu1 = Human("john", 21)
hu2 = Human("Bob", 22)

print(hu1)
print(hu2)

module2を実行するとこんな感じ。

test/module2.py
名前:john 年齢:21
名前:Bob 年齢:22

Process finished with exit code 0

備考

module2を実行した際、from module2 import Humanの時点でmodule2が全行読まれる。例えばmodule2に

class Human:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return "名前:" + str(self.name) + " 年齢:" + str(self.age)

print("test2")

print("test2")を追加し、module1を実行すると

test/module2.py
test2
名前:john 年齢:21
名前:Bob 年齢:22

Process finished with exit code 0

このようにtest2が表示される。