調子に乗るな、みんな頭がいい

ある程度負けることを認めながらつらつらと書いていきます。Twitterで育ちました。

PJ

  1. ブログ投稿サービス

qiita.com

Postgres使える○

内容△

 

  2.自動返信bot

qiita.com

面白そう○

内容○

Postgres×

 

 3.V Tuberのbot

qiita.com

面白そう○

内容△

ただしスクレイピングなどと組み合わせられそう

qiita.com

<全体の仕様>

  • LINEでユーザーが文字を入力
  • LINEで設定したWebhookのURLにリクエストが走る(今回の場合、HerokuでデプロイしたURL)
  • リクエストを受けてHerokuが起動
  • Herokuの中身のPython(main.py)が処理を始める
  • 続いてscrape.pyが処理を実行し、yahoo!ニュースへのスクレイピングを開始する
  • 該当記事があれば記事を、なければ「なかったよ!!」という文言を返す。
  • scrape.pyの結果がリクエストの結果として返され、LINEに表示される。

MVCモデルとは

MVCモデル

よくアプリの設計で言われているMVCモデルが、まさに今回開発したアプリ(というかFlask)で採用されているモデルです。

  • M(model):DBレコードをオブジェクトとして受け取る部分。今回のアプリで言う所のmodels.pyが該当します。
  • V(view):Webページを表示する部分。今回のアプリで言う所のtemplates/static/が該当します。
  • C(controller):httpリクエストを受け取って、modelを介してDB操作をしたり、viewを介してWebページを表示させたり等、中枢となる処理を実行する部分。今回のアプリで言う所のapp.pyが該当します。

 

次タスク(1/3)

  1. ソースコードGitHubに移植←イマココ
  2. きちんとしたDBへの移植
  3. 機械学習アプリケーションの実装

 

  1. ソースコードgithubに移植

    qiita.com

    のDay1を参考にする。

!

困ったこと:どうやらリモートアクセスができない。公開鍵を登録し直す必要がある。

qiita.com

こちらを参考にした。

f:id:you_suffer:20211109002000p:plain

無事に成功した。

ところで前にインターンしてた会社のgithub、もう抜けてたよなと思って確認したら、まだ入れた。俺にソースコード全部消されなくてよかったな。抜けました。

2.きちんとしたDBへの移植

 

APIの勉強(まとめ・ソースコード解読(2/2))

ロジック側(python

  • run.py

qiita.com

 

  1. 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"))

teratail.com

 

@app.route('/...')

というのは、このURLにユーザが入ってきたときに以下の関数を実行しろというものである

 

qiita.com

 

そんで、

  • 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)

qiita.com

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はユーザー側が情報を送信するのに適している

参考

qiita.com

③<input type="text" name="title" placeholder="title">

<input type="text" name="body" placeholder="body">

<input type="submit" value="Add">

 

qiita.com

 

これを見る限りでも、

HTML→pythonという流れのデータ受け渡しが行われているようだ。

APIの勉強(Day5/5)

前回まで、簡単なAPIをFlask上に作成した。

今回は、こちらの記事(

qiita.com

)で、

・POST

・DBへの接続

・レコードの追加・削除

・ログインなど

までを行う。

 

・POST

※htmlにフォームを用意する。押すとPOSTリクエストが出る?それがapp.pyに伝わる?nameがapp.pyから帰ってきて表示される?

※app.pyではルーティングに/indexにPOSTリクエストが来た場合の処理を追加。
その処理内で、フォームのテキスト要素を取得し、nameとしてhtml側に値を渡す。

 

・DBへの接続

(any directory)以下にmodelsフォルダを作成し、その中に__init__.pydatabase.pymodels.pyの3ファイルを作成

 

__init__.py:中身は空。モジュールを呼び出す際に__init__.pyがないといけないために作成する

database.py

テーブルのカラム情報を定義するためのクラスを格納します。
テーブル操作を行う際のレコード生成もこのクラスを通して行います。
今回は神社に対しての「お願い」を格納するためのテーブルを作成したいと思います。
カラム構成は

  • ID(int:キー情報)
  • title(String(128):お願いのタイトル)
  • body(text:お願いの内容)
  • date(datetime:お願いの投稿日時) にします。 models.pyを以下のように記載しましょう。

DBとの直接的な接続を確立している。

f:id:you_suffer:20211105111716p:plain

  1. database.pyと同じパスにonegai.dbというファイルを絶対パスで定義
  2. SQLiteを利用して1.で定義した絶対パスにDBを構築
  3. DB接続用インスタンスを生成
  4. Baseオブジェクトを生成して、
  5. そこにDBの情報を流し込む

>>> from models.database import init_db >>> init_db()

でエラーが出て、modelsというライブラリが入っていないのではないかとか右往左往。

結論から言うと解決。理由は、models.databaseというのはライブラリではなくて、/models/database.pyのことだった。書き方については以下の記事参照。

f:id:you_suffer:20211105115401p:plain

 

qiita.com

セットアップした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()

この順でやらなかったのが問題かもしれない

f:id:you_suffer:20211105160655p:plain

確かにPWがハッシュ化されている。

 

 

・requirements.txt

f:id:you_suffer:20211105175148p:plain

これだけでよかった

pip freeze > requirements.txtの問題点は以下。

①@以下に自分のPCの環境の絶対パスが入ってしまうため動かない

②不要なライブラリが多すぎる

 

※しかしデプロイしてみたwebサイトは動かない

 

takazawa.github.io

これを使ってみたところ、(出てきたファイル自体はダメだったのだが、)

Flaskが必要なことが判明。

f:id:you_suffer:20211105180426p:plain

入れたら...

f:id:you_suffer:20211105180522p:plain

できたゾ