APIの勉強(まとめ・ソースコード解読(2/2))
ロジック側(python)
- run.py
-
importは同じ階層にしか効かない。
サブディレクトリをimportしたい場合はおまじないを使う。
pythonは、実行されたscriptと同じ階層にあるdirectoryを探して、その中に __init__.py
があると、其のフォルダの中をimport対象として認識する。__init__.py
は空でいい。 $ touch __init__.py
でいい。
python3 run.pyを実行することで、from app.app import app
つまり、appディレクトリの中の、app.pyの中から、def app()を持ってくる。
if __name__ = __main__ がTrueなので、
app.run()
が動き、appディレクトリの中の、app.pyの中から、def app()が作動する
はずなのだが、今回def app()が見つからないので、app =
Flask(__name__)
が動いているのかもしれない(?)
→appという変数をimportしているのではないか?
- app.py
from flask import Flask,render_template,request,session,redirect,url_for
from models.models import OnegaiContent
from models.models import User
from models.database import db_session
from datetime import datetime
from app import key
from hashlib import sha256
modelsディレクトリの中のmodelsからclass OnegaiContent,class Userをimportしている
databaseからdb_session(→変数)をimportしている
app = Flask(__name__)
app.secret_key = key.SECRET_KEY
Flaskを起動し、appにインスタンスを入れる。
appインスタンスのsecret_key に key.pyの変数SECRET_KEYを入れる。
@app.route("/")
@app.route("/index")
def index():
if "user_name" in session:
name = session["user_name"]
all_onegai = OnegaiContent.query.all()
return render_template("index.html",name=name,all_onegai=all_onegai)
else:
return redirect(url_for("top",status="logout"))
@app.route('/...')
というのは、このURLにユーザが入ってきたときに以下の関数を実行しろというものである
そんで、
- database.py
- DBに入れる
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
import os
databese_file = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'onegai.db')
engine = create_engine('sqlite:///' + databese_file, convert_unicode=True)
db_session = scoped_session(sessionmaker(autocommit=False,autoflush=False,bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()
def init_db():
import models.models
Base.metadata.create_all(bind=engine)
from sqlalchemy import create_engine, Column, String, Integer from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker engine = create_engine('sqlite:///user.db')
# user.db というデータベースを使うという宣言です
Base = declarative_base()
# データベースのテーブルの親です
class User(Base):
# PythonではUserというクラスのインスタンスとしてデータを扱います
__tablename__ = 'users'
# テーブル名は users です
id = Column(Integer, primary_key=True, unique=True)
# 整数型のid をprimary_key として、被らないようにします
email = Column(String)
# 文字列の emailというデータを作ります
name = Column(String)
# 文字列の nameというデータを使います
def __repr__(self):
return "User<{}, {}, {}>".format(self.id, self.email, self.name)
Base.metadata.create_all(engine) # 実際にデータベースを構築します
SessionMaker = sessionmaker(bind=engine)
# Pythonとデータベースの経路です
session = SessionMaker()
# 経路を実際に作成しました
user1 = User(email="thisisme@test.com", name="Python")
# emailと nameを決めたUserのインスタンスを作りましょう(idは自動で1から順に振られます)
session.add(user1)
# user1 をデータベースに入力するための準備をします
session.commit()
# 実際にデータベースにデータを入れます。
- DBから出す
primary_keyで検索
例えば、idが2番目の人を取り出したいなら、
user = session.query(User).get(2)
としましょう。session.query(table名)
で、テーブルを指定して検索がかけられます。
primary_keyがidになっているので、get()の引数がidに合致するデータが取り出されます
値の大小で検索
idが3以上の人を探したいときには
user = session.query(User).filter(User.id >= 3).all()
print(user)
# [User<3, cobolisnotold@test.com, Cobol>, User<4, cplusminus@test.com, C>, User<5, kotlinissocute@test.com, Kotlin>, User<6, ilikeguido@test.com, Python>]
一致で検索
user = session.query(User).filter(User.name == "Python").all()
print(user)
# [User<1, thisisme@test.com, Python>, User<6, ilikeguido@test.com, Python>]
複数条件
user = session.query(User).filter(User.name == "Python", User.email == "thisisme@test.com").all()
print(user)
# [User<1, thisisme@test.com, Python>]
複数の条件を持たけることもでき、そのすべてが当てはまるもののみ返します。
いったんはこの程度で十分だと思います。
変更を加える
user = session.query(User).filter(User.name == "Python", User.email == "thisisme@test.com").all()
user.name = "Pythonista"
print(user)
# [User<1, thisisme@test.com, Pythonista>]
session.commit()
データを削除する
user = session.query(User).filter(User.name == "Python", User.email == "thisisme@test.com").all()
session.delete(user)
session.commit()
とすることでuserをデータベースから削除できます。
おわり
APIの勉強(まとめ・ソースコード解読(1/2))
- HTML
①<a href="/logout">ログアウトする</a>
HTMLでhref属性の使い方を現役エンジニアが解説【初心者向け】 | TechAcademyマガジン
パスを移動させることができる。遷移する。
今回は相対パス。
②<form action="/add" method="post">
URI = URLとURNのこと
formタグ
- 入力フォームや送信フォームを表示させたい時に使う
- formタグの間に他のタグを入れることによって様々な部品を配置することができる
- 表示されたフォームに入力されたデータは、送信ボタンを押すとCGIプログラムなどに送信されて処理される
- 処理の仕方を属性で指定する
- actionとmethodを定義することができる
action
- formタグに指定する属性で、必ず指定しなければならない
- フォームの送信ボタンを押して送信されるデータの送信先を指定する
- データの送信先のことをURIという
- 指定するのはデータを受け渡す処理をしてくれるサーバーのCGIプログラムのURI
method
- formタグに指定する属性で、必須ではない
- 送信するときの転送方法を指定する
- postとgetがある
get
- formタグのmethodをgetに指定すると、入力したフォーム内容のデータがURIにくっついて送信される
- 例 http://www.hogehoge.com/cgi.php?name=pippi&old=21&address=tokyo
- 例2 Googleで検索してURLが表示されるエリアを見ると、似たような文字列があるはず。これはあなたが検索したキーワードをURIの一番最後にくっつけて送信している
post
- formタグのmethodをgetに指定すると、入力したフォーム内容はURIとは別の場所に保管されてデータが送信される
- 入力したフォーム内容のデータは外側からの表示では見ることができないので安全性が高い
- getには送信するデータ量の制限がある
- getは送信したデータ内容が送信先のサーバーにログとして残ってしまうことがある
- postには送信するデータ量の制限がない
- 一概には言えないがgetはサーバー側にあるデータの取得に適している
- 一概には言えないがpostはユーザー側が情報を送信するのに適している
参考
③<input type="text" name="title" placeholder="title">
<input type="text" name="body" placeholder="body">
<input type="submit" value="Add">
これを見る限りでも、
HTML→pythonという流れのデータ受け渡しが行われているようだ。
APIの勉強(Day5/5)
前回まで、簡単なAPIをFlask上に作成した。
今回は、こちらの記事(
)で、
・POST
・DBへの接続
・レコードの追加・削除
・ログインなど
までを行う。
・POST
※htmlにフォームを用意する。押すとPOSTリクエストが出る?それがapp.pyに伝わる?nameがapp.pyから帰ってきて表示される?
※app.pyではルーティングに/index
にPOSTリクエストが来た場合の処理を追加。
その処理内で、フォームのテキスト要素を取得し、nameとしてhtml側に値を渡す。
・DBへの接続
(any directory)
以下にmodels
フォルダを作成し、その中に__init__.py
、database.py
、models.py
の3ファイルを作成
__init__.py
:中身は空。モジュールを呼び出す際に__init__.pyがないといけないために作成する
database.py
:
テーブルのカラム情報を定義するためのクラスを格納します。
テーブル操作を行う際のレコード生成もこのクラスを通して行います。
今回は神社に対しての「お願い」を格納するためのテーブルを作成したいと思います。
カラム構成は
- ID(int:キー情報)
- title(String(128):お願いのタイトル)
- body(text:お願いの内容)
- date(datetime:お願いの投稿日時) にします。 models.pyを以下のように記載しましょう。
DBとの直接的な接続を確立している。
database.py
と同じパスにonegai.db
というファイルを絶対パスで定義- SQLiteを利用して1.で定義した絶対パスにDBを構築
- DB接続用インスタンスを生成
- Baseオブジェクトを生成して、
- そこにDBの情報を流し込む
※>>> from models.database import init_db >>> init_db()
でエラーが出て、modelsというライブラリが入っていないのではないかとか右往左往。
結論から言うと解決。理由は、models.databaseというのはライブラリではなくて、/models/database.pyのことだった。書き方については以下の記事参照。
セットアップしたSQLiteのDBのonegaicontentsテーブルからレコードを全件引っ張ってきて、Webページに表示させる
・
レコードの追加・削除
・ログイン機能とセッション機能
- ログイン機能
- ユーザ新規登録機能
- ログイン中は左上に常に「{{ユーザ名}}神社」を表示
- ログアウト機能
DBにユーザの名前とパスワードを格納するためのusersテーブルを追加します。
まずmodels.py
にusersテーブルの定義を追加します。
ここで詰まった:
原因=models.pyでclass OnegaiContentsは認識されているのに、class Userが認識されていないために、DBで処理ができていない。
→再起動したら解決した。または、
from models.database import init_db
from models.models import User
init_db()
この順でやらなかったのが問題かもしれない
確かにPWがハッシュ化されている。
・requirements.txt
これだけでよかった
pip freeze > requirements.txtの問題点は以下。
①@以下に自分のPCの環境の絶対パスが入ってしまうため動かない
②不要なライブラリが多すぎる
※しかしデプロイしてみたwebサイトは動かない
これを使ってみたところ、(出てきたファイル自体はダメだったのだが、)
Flaskが必要なことが判明。
入れたら...
できたゾ