- 投稿日:2020-05-16T21:40:04+09:00
【vue】v-forで指定回数の表示と、10ずつの繰り返し処理
v-for
で1から10までの表示方法この方法で1から10までが表示されます
<template> <div id="app"> <ul v-for="n in 10" :key="n"> <li>{{ n }}</li> </ul> </div> </template>
v-for
で10個ずつ処理する方法通常のfor文の場合だと、このように増やしていきます
for (int i = 0; i < 10; i+10){ sum += 2; }しかし、vueの場合だと
i+10
のやり方ではうまくいかず
どのように10ずつ増やすのかがわからなかった。。。
解決方法は本当に簡単で、この方法で10ずつ表示ができます<template> <div id="app"> <ul v-for="n in 10" :key="n"> <li>{{ n * 10 }}</li> </ul> </div> </template>0から始める方法
<template> <div id="app"> <ul v-for="n in 10" :key="n"> <li>{{ (n - 1) * 10 }}</li> </ul> </div> </template>参考記事
- 投稿日:2020-05-16T21:40:04+09:00
【vue】v-forでセレクトボックスに指定回数の表示と、10ずつの繰り返し処理
v-for
で1から10までの表示方法この方法で1から10までが表示されます
<template> <div id="app"> <ul v-for="n in 10" :key="n"> <li>{{ n }}</li> </ul> </div> </template>
v-for
で10ずつ処理する方法通常のfor文の場合だと、このように増やしていきます
for (int i = 0; i < 10; i+10){ sum += 2; }しかし、vueの場合だと
i+10
のやり方ではうまくいかず
どのように10ずつ増やすのかがわからなかったです。
解決方法は本当に簡単で、この方法で10ずつ表示ができます<template> <div id="app"> <ul v-for="n in 10" :key="n"> <li>{{ n * 10 }}</li> </ul> </div> </template>セレクトボックスで10ずつ表示する方法
さて、自分が対処方法をみつけるのに時間がかかってしまったのがセレクトボックスに10ずつ表示させる方法でした。
{{ n * 10 }}
の方法を考えれば簡単なのですが、
どこにi+10
の要素を書けばいいのかに固執してしまっていました。セレクトボックスで10ずつ表示させる方法も本当に簡単でこのようにやります
<template slot-scope="hoge"> <el-select v-model="hoge" placeholder="Select"> <el-option v-for="n in 10" :key="n" :value="n * 10"> </el-option> </el-select> </template>
:value
のところに同じようにかけばいいんですね。
v-for
にかいたりkey
の部分にi+10
の要素を入れようとしてまったくうまくいっていなかったです。通常のfor文のやり方につられてしまい、ずっと
+
を使用して対処しようとしていたのもよくなかったです。0から始める方法
ちなみに0から始める方法はこのようにやります
<template> <div id="app"> <ul v-for="n in 10" :key="n"> <li>{{ (n - 1) * 10 }}</li> </ul> </div> </template>参考記事
- 投稿日:2020-05-16T18:26:01+09:00
DataTablesを使って遊戯王カードの表を作る!(1)
はじめに
こんにちは。hyです。 現在は某IT企業でエンジニアとして働いています。大学4年のときにweb系の会社で開発のアルバイトをしていました。そこで得た知識を今更ながらアウトプットしていきたいと思ったので、得た知識を使って簡単なアプリケーションを作っていきたいと思います。
今回は,バイト先で使用していたjQueryライブラリのDataTablesを使って遊戯王カードを表示させるアプリを作っていこうと思います。使う技術
- DataTables
- 簡単に綺麗な表や機能を追加できるjQueryライブラリ
- Mustache.js
- javascriptのテンプレートエンジンで,今回は主にDataTableと併用して使います。
- Vue.js
- javascriptのフレームワークの一つ。学習コストが低いことが特徴
- Yu-Gi-Oh! API by YGOPRODeck
- 遊戯王カードの画像や効果などの情報を取得できるAPI
完成品
以下のような物を作りました!
See the Pen datatable-app by higakin (@hgaiji) on CodePen.
最後に
次回、これらのコードについて解説してきたいと思います。何かコメントなどがある人はお気軽にお願いします。
- 投稿日:2020-05-16T17:45:09+09:00
ここが変だよVuex
こんにちは
フロントエンドフレームワークのVue.js/Nuxt.jsにおいて、個人的に一番理解が難しかったVuexについて、僕が「ここ変だな!」
と感じたポイント2つと、なぜ変だなと感じたのか、そしてその答えをここに記していきます。。。
1つめの疑問 そもそもなんでVuexを使うの?
まず僕がVuexで最初に「!?」となったのが、なんでVuex使うの?という点です。
Vuexって状態管理ライブラリで、主にAPIとの接続したデータを保持するため使われることが多いと思うんですが、別にVuex使わなくてもAPIとの接続はできるし、emitとかpropsでデータ渡せばよくね!?
って思いました。
しかもVuexあるとコードが冗長になる。。。
なんでVuexなんてややこしくなるものをわざわざ使うんだろうか。と、すごい不思議でした。疑問の答え
なんでVuexを使うか、それは
アプリケーションの状態全体を1か所に表現して、アプリケーションをより組織化することができるから
だそうです。
以下のQiita記事にとてもわかりやすく書いてあります。
Vue.js + Vuexでデータが循環する全体像を図解してみた
ルートコンポーネント>子コンポーネント>孫コンポーネント>ひ孫コンポーネント>...
と続いていくと、今自分が開発しているコンポーネントが何層目にいるのか全くわからなくなります。
この現象はまるで映画「インセプション」の世界。夢の中の夢に入り続けるうちにどこが現実かわからなくなるあれです。要するに、コンポーネントが深くなり複雑になるにつれバケツリレーみたいにデータを渡すのが大変になるので、それを防ぐためにVuexを使うようです。
確かに、Vuexを使えば
this.$store.state.hoge
これ一発でデータを取れる。
なんで、コンポーネントがめちゃくちゃネストするような複雑で大規模なアプリケーションだとVuexは必須で、小中規模だとそんな積極的に使わなくても良いのかな〜。と思います。2つめの疑問 actionsいらなくね?
次にVuexで「!?」となったのがactionsです。
以下はVuex公式ドキュメントの画像です。
Vuexってこんな感じで、
this.$store.dispatch('hoge/fuga', params)
でactionsにdispatchして、actions内でAPIからデータを取ってきて
commit('SET_HOGE', responseData)
みたいな感じでmutationsにデータをコミットします。
でmutationsで
SET_HOGE(state, responseData) {
state.hoge = responseData
}
みたいな感じでstateのデータを書き換えます。
これがVuexの流れなんですが、僕は、こう思いました。いや、actionsいらんやろ。
コンポーネントから直接commitできるんだし、dispatchなんかしないでcommitしてmutations内でAPIからデータ取ってきて、そのままstateのデータ書き換えればええやん。
わざわざ間にactionsを挟む意味がわからん。
と疑問の答え
この疑問に対する答えはVuexの公式ドキュメントに書いてありました。
公式ドキュメントによるとアクションは store.dispatch がトリガーとなって実行されます:
store.dispatch('increment')
これは一見ばかげて見えるかもしれません。つまり、カウントをインクリメントしたいときに、どうして直接 store.commit('increment') を呼び出してミューテーションをコミットしないのか、と。ミューテーションは同期的でなければならないというのを覚えていますか?アクションはそうではありません。アクションの中では非同期の操作を行うことができます。だそうです。なるほど。。。
Vuexに慣れていない頃はactionsを挟む意味がわからんと思っていましたが、今ではstate、mutations、actionsと各処理の責務が明確になっていいなと思います。
お疲れ様でした。
- 投稿日:2020-05-16T17:45:09+09:00
ここが変だよVuex
こんにちは
フロントエンドフレームワークのVue.js/Nuxt.jsにおいて、個人的に一番理解が難しかったVuexについて、僕が「ここ変だな!」
と感じたポイント2つと、なぜ変だなと感じたのか、そしてその答えをここに記していきます。。。
1つめの疑問 そもそもなんでVuexを使うの?
まず僕がVuexで最初に「!?」となったのが、なんでVuex使うの?という点です。
Vuexって状態管理ライブラリで、主にAPIとの接続したデータを保持するため使われることが多いと思うんですが、別にVuex使わなくてもAPIとの接続はできるし、emitとかpropsでデータ渡せばよくね!?
って思いました。
しかもVuexあるとコードが冗長になる。。。
なんでVuexなんてややこしくなるものをわざわざ使うんだろうか。と、すごい不思議でした。疑問の答え
なんでVuexを使うか、それは
アプリケーションの状態全体を1か所に表現して、アプリケーションをより組織化することができるから
だそうです。
以下のQiita記事にとてもわかりやすく書いてあります。
Vue.js + Vuexでデータが循環する全体像を図解してみた
ルートコンポーネント>子コンポーネント>孫コンポーネント>ひ孫コンポーネント>...
と続いていくと、今自分が開発しているコンポーネントが何層目にいるのか全くわからなくなります。
この現象はまるで映画「インセプション」の世界。夢の中の夢に入り続けるうちにどこが現実かわからなくなるあれです。要するに、コンポーネントが深くなり複雑になるにつれバケツリレーみたいにデータを渡すのが大変になるので、それを防ぐためにVuexを使うようです。
確かに、Vuexを使えば
this.$store.state.hoge
これ一発でデータを取れる。
なんで、コンポーネントがめちゃくちゃネストするような複雑で大規模なアプリケーションだとVuexは必須で、小中規模だとそんな積極的に使わなくても良いのかな〜。と思います。2つめの疑問 actionsいらなくね?
次にVuexで「!?」となったのがactionsです。
以下はVuex公式ドキュメントの画像です。
Vuexってこんな感じで、
this.$store.dispatch('hoge/fuga', params)
でactionsにdispatchして、actions内でAPIからデータを取ってきて
commit('SET_HOGE', responseData)
みたいな感じでmutationsにデータをコミットします。
でmutationsで
SET_HOGE(state, responseData) {
state.hoge = responseData
}
みたいな感じでstateのデータを書き換えます。
これがVuexの流れなんですが、僕は、こう思いました。いや、actionsいらんやろ。
コンポーネントから直接commitできるんだし、dispatchなんかしないでcommitしてmutations内でAPIからデータ取ってきて、そのままstateのデータ書き換えればええやん。
わざわざ間にactionsを挟む意味がわからん。
と疑問の答え
この疑問に対する答えはVuexの公式ドキュメントに書いてありました。
公式ドキュメントによるとアクションは store.dispatch がトリガーとなって実行されます:
store.dispatch('increment')
これは一見ばかげて見えるかもしれません。つまり、カウントをインクリメントしたいときに、どうして直接 store.commit('increment') を呼び出してミューテーションをコミットしないのか、と。ミューテーションは同期的でなければならないというのを覚えていますか?アクションはそうではありません。アクションの中では非同期の操作を行うことができます。だそうです。なるほど。。。
Vuexに慣れていない頃はactionsを挟む意味がわからんと思っていましたが、今ではstate、mutations、actionsと各処理の責務が明確になっていいなと思います。
お疲れ様でした。
- 投稿日:2020-05-16T17:15:35+09:00
Vue.jsでアップロードされた画像の中心から正方形にくり抜いてexif情報処理してFirebaseStorageにアップする
自分用
詰め込みすぎだけど色々なアプリで使うため<input type="file" accept="image/*" style="display:none;" @change="upload"/> <canvas id="canvas" hidden></canvas>upload(ev) { const TRIM_SIZE = 512 let blob = null const storageRef = firebase.storage().ref() if (!ev) return const file = ev.target.files[0] if (file.type !== 'image/jpeg' && file.type !== 'image/png') { return } const image = new Image() const reader = new FileReader() reader.onload = e => { image.onload = () => { let width, height, xOffset, yOffset if (image.width > image.height) { height = TRIM_SIZE width = image.width * (TRIM_SIZE / image.height) xOffset = -(width - TRIM_SIZE) / 2 yOffset = 0 } else { width = TRIM_SIZE height = image.height * (TRIM_SIZE / image.width) yOffset = -(height - TRIM_SIZE) / 2 xOffset = 0 } const canvas = $('#canvas') .attr('width', TRIM_SIZE) .attr('height', TRIM_SIZE) const ctx = canvas[0].getContext('2d') ctx.clearRect(0, 0, width, height) let orientation = '' EXIF.getData(file, () => { orientation = file.exifdata.Orientation switch (orientation) { case 2: ctx.transform(-1, 0, 0, 1, width, 0) break case 3: ctx.transform(-1, 0, 0, -1, width, height) break case 4: ctx.transform(1, 0, 0, -1, 0, height) break case 5: ctx.transform(0, 1, 1, 0, 0, 0) break case 6: ctx.transform(0, 1, -1, 0, height, 0) break case 7: ctx.transform(0, -1, -1, 0, height, width) break case 8: ctx.transform(0, -1, 1, 0, 0, width) break default: break } ctx.drawImage(image, xOffset, yOffset, width, height) const base64 = canvas.get(0).toDataURL('image/jpeg') const bin = atob(base64.split('base64,')[1]) const len = bin.length const barr = new Uint8Array(len) let i = 0 while (i < len) { barr[i] = bin.charCodeAt(i) i += 1 } blob = new Blob([barr], { type: 'image/jpeg' }) ctx.clearRect(0, 0, width, height) const uploadRef = storageRef.child(//パス ) uploadRef.put(blob).then(() => { uploadRef.getDownloadURL().then(url => { //URLをどうにかする処理 }) }) }) } image.src = e.target.result } reader.readAsDataURL(file) },
- 投稿日:2020-05-16T16:37:54+09:00
Vue.js文法チートシート
この内容について
この内容は、私が運営しているサイトに、より見やすく掲載しているので、よければそちらもご活用ください。
Vue.jsチートシート | コレワカVue.jsとは
Vue.jsはUI構築のためのJavaScriptプログレッシブフレームワークのこと
Vue.js公式サイト基本的な書き方
HTML<div id="app"> <!-- Vue.js適用範囲 --> </div>Vuevar vm = new Vue({ el: '#app' });オプション
el
Vue.jsの機能を適用するDOMの指定
See the Pen
Vue.js_el by engineerhikaru (@engineerhikaru)
on CodePen.
data
データを保持する(データの変数化)。{{ 変数名 }}で出力可能
See the Pen
Vue.js_data by engineerhikaru (@engineerhikaru)
on CodePen.
methods
v-onのイベントハンドラとして使用
See the Pen
Vue.js_ methods by engineerhikaru (@engineerhikaru)
on CodePen.
computed
算出プロパティ。データの自動更新をし、計算結果はキャッシュに保存。getでは必ず戻り値が必要
See the Pen
Vue.js_ computed by engineerhikaru (@engineerhikaru)
on CodePen.
watch
監視プロパティ。特定のプロパティの値の変更を監視し、変更時に設定した関数を実行
See the Pen
Vue.js_watch by engineerhikaru (@engineerhikaru)
on CodePen.
template
文字列,HTMLコードをテンプレート化する。コンポーネント機能と共に使用
See the Pen
Vue.js_template by engineerhikaru (@engineerhikaru)
on CodePen.
props
コンポーネント機能でデータを参照する
See the Pen
Vue.js_props by engineerhikaru (@engineerhikaru)
on CodePen.
created
インスタンスが作成された後(DOMは生成されていない)に実行するオプション
See the Pen
Vue.js_created by engineerhikaru (@engineerhikaru)
on CodePen.
mounted
DOMが生成された後に実行するオプション
See the Pen
Vue.js_mounted by engineerhikaru (@engineerhikaru)
on CodePen.
ディレクティブ
v-text
テキストデータを出力
See the Pen
Vue.js_v-text by engineerhikaru (@engineerhikaru)
on CodePen.
v-html
HTMLデータを出力
See the Pen
Vue.js_v-html by engineerhikaru (@engineerhikaru)
on CodePen.
v-show
条件分岐(createdフックは最初のみ実行)
See the Pen
Vue.js_v-show by engineerhikaru (@engineerhikaru)
on CodePen.
v-if, v-if-else, v-else
条件分岐
See the Pen
Vue.js_v-if by engineerhikaru (@engineerhikaru)
on CodePen.
v-for
ループする
See the Pen
Vue.js_v-for by engineerhikaru (@engineerhikaru)
on CodePen.
v-on, @
イベントを処理する
See the Pen
Vue.js_v-on by engineerhikaru (@engineerhikaru)
on CodePen.
v-bind, :
HTMLの属性を指定する
See the Pen
Vue.js_v-bind by engineerhikaru (@engineerhikaru)
on CodePen.
v-model
入力データと指定したデータをリンクする
See the Pen
Vue.js_v-model by engineerhikaru (@engineerhikaru)
on CodePen.
v-pre
{{}}をそのまま表示する
See the Pen
Vue.js_v-pre by engineerhikaru (@engineerhikaru)
on CodePen.
v-cloak
{{}}が表示されるのを防ぐ(最初に表示される事がある)
See the Pen
Vue.js_v-cloak by engineerhikaru (@engineerhikaru)
on CodePen.
v-once
レンダリングを一度だけ実行(データの変更を適用しない)
See the Pen
Vue.js_v-once by engineerhikaru (@engineerhikaru)
on CodePen.
グローバル設定
silent
警告,エラーメッセージの表示,非表示を指定する
VueVue.config.silent = true;この内容について
この内容は、私が運営しているサイトに、より見やすく掲載しているので、よければそちらもご活用ください。
Vue.jsチートシート | コレワカ
- 投稿日:2020-05-16T15:58:02+09:00
スプレッドシートをDB代わりにGASのWebアプリを作成しデータ更新させてみた。Vue版、ハマったところinputの再描画編~~
はじめに
Vueに対応していこう~。ということで始めたわけですが、
inputの再描画がハマりにハマって、くじけそうになったんで残しておきます。結論
ここを見ている方は、たぶん、同じ症状の方だと思うのでとっとと結論書きます。
私は、モーダル表示にして 回避 しました!
そうです。すみません。若干逃げてます。
ですが、私の作りたかったものからすると、ちょうど都合がよかったのです・・・なぜモーダルだとうまくいくのか
モーダル表示をする際に、モーダルにするためのv-showに設定したプロパティをtrueにします。
それと同時に、上記の内側のタグのv-ifもtrueにするようにしました。
こんな感じです。<div id="modal" v-show="showContent" class="overlay"> <div id="modal_content" v-if="dispDetails" class="content"> <!-- さらに内側のタグモーダルにすることで、モーダルを表示する際には、showContent も dispDetails も共にtrueにします。閉じる際は共にfalseにします。(上記の場合、同じプロパティを使用しても問題ないとは思いますが明示的に分けました。)
dispDetailsがTrue、Falseに切り替わることで、v-ifが設定されたタグよりも内側のタグがきちんと再描画されるようになったのだと思われます。感想
表示できるようになって本当にほっとしました。
Vue版、ハマったところcheckboxの再描画編~~も投稿しました。
こちらもよろしくお願いします
- 投稿日:2020-05-16T15:55:38+09:00
Vue.jsで東京都の今日の天気を表示するWebサイトを作るコピペサンプル
簡単なサンプルです。
Vue.jsとaxiosで簡単なデータ連携をします。
作るもの
こんな感じでボタンを押すと今日の天気を表示するWebサイトを作ります。
使うAPI
OpenWhethermapのAPIを作います。無料である程度(雑)使えます。
https://openweathermap.org/api
APIキーを取得しましょう。
ログイン後ここにアクセスするとキーが表示されます。
コピペ用コード
一箇所だけ、変更が必要です。
appid=ここにOpenWeathermapのAPIキーを指定
と書いているところに自身で取得したAPIキーを指定しましょう。index.html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <p>今日の天気は{{ weather }}で、気温は{{ temp }}度です。</p> <button v-on:click="getData()">今日の東京の天気をAPIで取得!</button> <p> <a href="https://openweathermap.org/api">openweathermapから取得しています。</a> </p> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script> var app = new Vue({ el: '#app', data: { weather: 'xxxx', temp: 'yyyy' }, methods: { getData: async function(){ const URL = `https://api.openweathermap.org/data/2.5/weather?id=1850147&units=metric&appid=ここにOpenWeathermapのAPIキーを指定`; const response = await axios.get(URL); this.weather = response.data.weather[0].main; this.temp = response.data.main.temp; // console.log(response.data); }, }, // mounted: function(){ // } }) </script> </body> </html>試す。
ローカルのindex.htmlをブラウザで開いたり、live severやどこかにデプロイしたりして挙動確認をしましょう。
- 投稿日:2020-05-16T15:48:32+09:00
Vue.jsプロジェクトのつくりかた※自分用メモ
- ターミナルでcdプロジェクトを作成したいディレクトリに移動。
vue create プロジェクト名
設定を選ぶので、defaultで
cd 作ったプロジェクト名
yarn serve で完成!
おまけ
test.jsconsole.log()↑のようにやりたいときは
改行
```
コード
```
改行 でコードが挿入できる!```の後にファイル名を入れると、ファイル名も表示される。言語を指定するとそれにあったように色つけてくれる!
- 投稿日:2020-05-16T12:51:17+09:00
doc2vec・scikit-learn・Django・Vue.js・Herokuで文章から性格診断する機械学習webアプリを作った備忘録
はじめに
タイトルの通り、doc2vec・scikit-learn・Django・Vue.js・Herokuなどいろいろ駆使し、機械学習Webアプリケーションをフルスクラッチ実装した。
機械学習のモデリング手法、またはSPA構築のHowToはそれら単体では紹介されているが、それらをフルスクラッチで構成するノウハウは未だあまり出回っていないように思える。
まずは自分の備忘のため、そして特に作った機械学習モデルをWebアプリ化して公開してみたい人のため、アプリの構成や躓いたポイントなどを記事に残す。この記事のスコープ
含む内容
- Webアプリを実装するのに使用したライブラリ
- Webアプリのディレクトリ構成
- 機械学習モデルとDjangoの連携
- Vue.js、Django REST Frameworkを使用したSPA(Single Page Application)実装
- Herokuデプロイの設定Tips
含まない内容
- ライブラリ単体の(doc2vec, scikit-learn, ...)説明や、Web開発の基礎(フロントエンドやREST Framework)の説明。各種チュートリアルを参考にされたい。
- 自然言語処理・機械学習の理論の説明。筆者は未だ理解が浅く、理論に関する言及はなるべく控える。
- ソースコード。いつかGithubで公開するかも。
- アプリの精度に対する議論。そもそも文章から性格を判断すること自体ナンセンスだし、学習のためのジョークアプリという位置づけにしたい。
作ったWebアプリの紹介
URL
http://personalityestimator.herokuapp.com/サービスの説明
- 英文をInputとし、MBTIメソッドに基づいた16タイプの性格診断を行う。
- 16タイプの指標は、2値をもつ4つの指標の乗算(2^4 = 16)で表される。文章を入力することで、それぞれの指標にどれだけ寄っているかをパーセンテージで算出することができる。
- 試しにトランプ大統領のスピーチをInputするとENTP - The Debater(討論者)と評価される。なかなかそれっぽい。
参考:MBTI 4指標(MBTI協会サイトより引用)
指標 基準 興味関心の方向 外向(Extroverts) vs 内向(Introverts) ものの見方 感覚(Sensors) vs 直観(i Ntuitives) 判断のしかた 思考(Thinkers) vs 感情(Feelers) 外界への接し方 判断的態度(Perceivers)・知覚的態度(Judgers) システムの説明
- 教師データとしてKaggle公開のデータセット「(MBTI) Myers-Briggs Personality Type Dataset」を使用している。レコードの単位は被験者単位で、カラムは性格診断結果(Type)と投稿した文章(Posts)の二つを持つ。
- 学習は、投稿した文章(Posts)をdoc2vecで100次元ベクトル化し、それらに対して2値分類を行うモデル(ロジスティック回帰)を4つ実装している。
備忘録
ランタイム・仮想環境
Pythonバージョンは
python-3.7.3
を使用。仮想環境はanyenv + pyenv(インタプリタ切り替え) + virtualenv(パッケージ切り替え) + virtualenvwrapperを使用している。
尚、Anacondaは使用していない。当初入れていたがアプリ実装時はすべて削除している。(condaとpip:混ぜるな危険)ブループリント
当Webアプリのブループリント(構成図)を説明する
No. コンポーネント 説明 ① FE Vue.jsを採用。axiomライブラリを使用してAPIを非同期でコールし、返却値をレンダリングする。
CDN版を採用し、状態管理(vuex)やルーティング(vue-rooter)は実装していない。② API Django REST Frameworkを採用。フォームで入力した文章をリクエストし、モデルの予測結果をレスポンスする。 ③ DB SQ Liteを採用。プロジェクト開始時に自動で付属するだけで、今回特にデータの参照・登録は行っていない。 ④ Model Gensim (doc2vec)を単語のベクトル化、Scikit-Learnをモデリングに採用。モデルは各指標ごとに2値分類を行うモデルを4つ実装。 ⑤ Server Herokuを採用。①〜④を丸ごと1つのAppとしてデプロイしている。 requirements.txt
仮想環境にインストールした各種ライブラリを説明する(google-api-coreとか、明らかに不要そうなものも入っている気がする・・・)。基本すべてpipでインストール可能。
requirements.txtboto3==1.12.36 botocore==1.15.36 cachetools==4.0.0 certifi==2019.11.28 chardet==3.0.4 dj-database-url==0.5.0 Django==2.2.5 # ① django-heroku==0.3.1 # ② djangorestframework==3.10.3 # ① docutils==0.15.2 gensim==3.8.1 # ③ google-api-core==1.16.0 google-auth==1.13.1 google-cloud-core==1.3.0 google-cloud-storage==1.27.0 google-resumable-media==0.5.0 googleapis-common-protos==1.51.0 gunicorn==20.0.4 # ② idna==2.9 jmespath==0.9.5 joblib==0.14.1 numpy==1.18.1 pandas==1.0.1 protobuf==3.11.3 psycopg2==2.8.5 pyasn1==0.4.8 pyasn1-modules==0.2.8 python-dateutil==2.8.1 pytz==2019.3 requests==2.23.0 rsa==4.0 s3transfer==0.3.3 scikit-learn==0.22.2.post1 # ③ scipy==1.4.1 six==1.14.0 smart-open==1.10.0 sqlparse==0.3.1 urllib3==1.25.8 whitenoise==4.1.3①:Django関係のライブラリ
django
はWebフレームワーク、djangorestframework
はその中でもREST API実装特化。両方ともpipでインストールする。②:Heroku関係のライブラリ
djangoアプリをherokuにデプロイする際に必要となる。
django-heroku
をインストールすれば依存パッケージのwhitenoise
やdj-database-url
も一緒にインストールされる。③:機械学習関係のライブラリ
gensim
,scikit-learn
を導入する。モデルの学習はjupyterで別で学習しているが、モデルの予測処理には必要。他、numpy
,pandas
等も一緒に導入する。ディレクトリ構成
当Webアプリのディレクトリ構成を説明する。
personalityestimator ├── Procfile # ② ├── apiv1 # ① │ ├── __init__.py │ ├── __pycache__ │ ├── admin.py │ ├── apps.py │ ├── clfs ③ │ │ ├── logreg_ie.pickle │ │ ├── logreg_pj.pickle │ │ ├── logreg_sn.pickle │ │ ├── logreg_tf.pickle │ │ └── model.pickle │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── serializers.py │ ├── tests.py │ ├── urls.py │ └── views.py ├── config # ① │ ├── __init__.py │ ├── __pycache__ │ ├── local_settings.py # ④ │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── db.sqlite3 ├── get_random_secret_key.py # ④ ├── manage.py ├── mbti # ① │ ├── __init__.py │ ├── __pycache__ │ ├── admin.py │ ├── apps.py │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── 0002_..... │ │ ├── __init__.py │ │ └── __pycache__ │ ├── models.py │ ├── tests.py │ └── views.py ├── requirements.txt # ② ├── runtime.txt # ② ├── static │ └── style.css └── templates └── index.html①:django プロジェクト・アプリケーション
指定ファイルは以下のコマンドで生成している。
(venv) $ django-admin startproject config . (venv) $ python manage.py startapp mbti (venv) $ python manage.py startapp apiv11プロジェクト、2アプリケーション(mbti, apiv1)で構成する。
プロジェクト開始時、config .
と指定することで、ベースディレクトリと設定ディレクトリ(config)が同じ名前になることを回避している。アプリケーションはモデルのみを定義するmbti
, REST API機能を有するapiv1
の2つを作成している。
上記コマンド以外では、以下を手動で実行している。
apiv1/serializers.py
を追加。REST Framework上でのデータの保持を行う役割を持つ。バリデーション等もこのファイルで定義する。static
、templates
ディレクトリを追加し、静的ファイルやindex.htmlを格納する。settings.py
も同ディレクトリを検索するように一部書き換える。②:Herokuデプロイ設定
Herokuデプロイ時には、
Procfile
、requirements.txt
、runtime.txt
の3つを作成する。Procfile
はアプリを動かす指示書の役割、requirements.txt
は使用するライブラリをherokuに知らせる役割、runtime.txt
は使用するPythonのバージョンを知らせる役割を持つ。③:モデルの格納
学習済のgensim, doc2vecのモデルをpickle化し、
clfs
ディレクトリに格納している。
model.pickle
は単語のベクトル化、logreg_XX.pickle
はそれぞれの指標に対してロジスティック回帰で2値分類する。④:秘密情報の設定
次節のはまったポイント③を参照。
はまったポイント
①Procfileの設定によるHerokuデプロイエラー
問題
Herokuでデプロイには成功するが、WebアプリにアクセスするとApplication Errorが発生する。解決策
Procfileのプロジェクト名の記載欄に、間違えてルートディレクトリ名を記載していたことが原因だった。
上記コマンドstartproject config .
の通り、このWebアプリの正しいプロジェクト名はconfig
とである。一般的で紹介されているディレクトリ構成と異なっているためなかなか気づけなかった。(誤)web: gunicorn personalityestimator(ルートディレクトリ名).wsgi --log-file - (正)web: gunicorn config(設定ファイル名).wsgi --log-file -②index.html上のデリミタ「{{}}」がDjango, Vue.jsで重複する
問題
今回Vue.jsはCDN版を採用しているため、index.html
に<script>タグで直接Vue.jsを書き込んでいる。
Djangoテンプレートの変数表示構文とVue.jsのMustache構文が両方ともデリミタ「{{}}」が使用されているため、そのままの設定ではバッティングする。解決策
Vue.jsのデリミタを変更する。Vue.options.delimiters
でデリミタを「#{}」に変更して衝突を回避する。index.html<!DOCTYPE html> {% load static %} <html lang="en"> <head> <meta charset="UTF-8"> ... <title>PersonalityEstimator</title> <!-- CSS --> <link rel="stylesheet" href="https://unpkg.com/ress/dist/ress.min.css"> <link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet"> <link href="{% static 'style.css' %}" rel="stylesheet"> <!-- JS --> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <!-- axios --> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> </head> <body> <div id="app"> ... </div> </body> <script> Vue.options.delimiters = ['#{', '}'] // ポイント var app = new Vue({ el: '#app', data: { ... }, methods: { ... }) </script>③DjangoのSECRET_KEYをプロダクション環境に公開しないようにする
問題
settings.py
に初期値コメント「SECURITY WARNING: keep the secret key used in production secret!」の通り、SECRET_KEY
はプロダクション環境からは見えないようにしたい。解決策
settings.py
から新たにlocal_settings.py
を複製し、SECRET_KEY
はlocal_settings.py
のみに記載する。settings.py
のSECRET_KEY
はlocal_settings.py
からインポートする。settings.pyimport os import django_heroku from os import environ from socket import gethostname # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! HOSTNAME = gethostname() if 'local' in HOSTNAME: from . import local_settings SECRET_KEY = local_settings.SECRET_KEY else: SECRET_KEY = environ['SECRET_KEY'] # SECURITY WARNING: don't run with debug turned on in production! DEBUG = False ALLOWED_HOSTS = ['127.0.0.1', '.herokuapp.com'] ...
local_settings.py
は.gitignore
に記載しgit管理されないようにする。
DEBUG = False
に書き換えるのも忘れないように。尚、上記ディレクトリ構成にあった
get_random_secret_key.py
は新しくSECRET_KEY
を生成する際に使用した。一度うっかり秘密鍵をgit管理に上げてしまったので、鍵の再生成を行った。get_random_secret_key.pyfrom django.core.management.utils import get_random_secret_key secret_key = get_random_secret_key() text = 'SECRET_KEY = \'{0}\''.format(secret_key) print(text)④その他
django-heroku
のインストール時に同梱されるwhitenoise
は最新バージョンで5系になっている。最新の情報が載っている参考サイトでもほぼ4系を採用していたため、アンインストールした後再度4系をインストールした。- CSS。拡大・縮小による表示崩れやレスポンシブ対応の工夫をしている。親構造に
max-width
を指定するwrapperクラスをあちこちで指定している。まだ嵌ってるポイント・Todo
本アプリのWebアプリの残課題を記載する。解決策をご存知の方がいらっしゃればコメントをいただきたい。
- index.htmlに記載されている<script>をjsファイルに分離し、staticに格納したい。main.jsファイルを読み込む手法も検証したが、どうやっても正常に読み込まれず断念。
- clsf(モデル)の格納場所を変えたい。何となくapiv1の中ではなくstaticの中に置くべきな気がしているが、あるべきが何かを知りたい。
- apiv1/view.pyをリファクタリングしたい。Typeの設定("INTJ": "The Architect"など)は同ファイルにベタ書きで持っているので、モデルに移植してマスタテーブル化したい。が、2つのModelを参照してレスポンスする方法がよくわからず断念。
- Modelの精度は上げたい。次は深層学習にチャレンジするつもり。
参考にしたサイト・書籍
①:(Web)doc2vec and logistic regression
URL
https://www.kaggle.com/wpncrh/doc2vec-and-logistic-regression説明
当アプリで使用するデータセットを使用したKaggleのKernel。
Doc2Vec
による単語のベクトル化や、前処理の方法はこのKernelを参考にしている。本アプリではこのKernelに実装されている前処理に加えて、URLや記号を正規表現で取り除いている。②:(動画)Build a Machine Learning API with Django
URL
https://youtu.be/tDnAcbYROSI説明
Django REST FrameworkとMachine Learningをかけ合わせたアプリ実装を全6回で説明している。範囲はモデル実装からDjangoアプリ作成、Herokuにデプロイするところまですべて。
モデルをPickle化してDjangoアプリ内に入れるアイデアはこの動画から着想を得た。一方、Django REST Frameworkの記法は若干怪しいように見受けられるので、Djangoの学習はチュートリアルに沿うことをおすすめする。後半のHerokuデプロイは観ていない。
全編インド人による英語の講義。③:(書籍)現場で使えるDjangoの教科書
URL
現場で使える Django の教科書《基礎編》
https://booth.pm/ja/items/1308742現場で使える Django REST Framework の教科書
https://booth.pm/ja/items/1559869説明
Django及びDjango REST Frameworkを体系的に学ぶには最もおすすめ。
Webアプリのディレクトリ構成や、DjangoとVue.jsの連携、デリミタの重複回避はこの書籍を参考にした。特にDjangoとVue.jsの連携はサンプルプロジェクトがそのまま載っているので大変参考になる。④(Web)『完全版』Djangoアプリをherokuにデプロイ!
URL
http://digital-tree.xyz/blogs/1169説明
DjangoアプリケーションをHerokuにデプロイする手順が記載されている。
2019年9月の記事のため(2020年5月現在は)、比較的最新。⑤(Web)Djangoでの"秘密にしたい値"の取り扱い - ティッシュ残り一枚
URL
https://tsukachu.hatenablog.com/entry/handling_secret_keys説明
Heroku、Github等で秘密鍵を公開しないようにするための実装方法の記載がある。
嵌ったポイント③「DjangoのSECRET_KEYをプロダクション環境に公開しないようにする」は本記事を参考にしている。⑥(書籍)1冊ですべて身につくHTML & CSSとWebデザイン入門講座
URL
https://www.amazon.co.jp/dp/4797398892/ref=cm_sw_em_r_mt_dp_U_Of2VEbSY2RKCE説明
HTMLとCSSの説明。
アプリ構想時点でCSSが全く分からなかったのでこの書籍で1から学習した。スマホ・PC両対応したレスポンシブデザインを作るのにも参考にしている。⑦その他
Python自体はPythonデータサイエンスハンドブックや、みんなのPython 第4版で学習した。
終わりに
筆者はエンジニアではなく、趣味で一人コードを書いている。このアプリも空き時間を使って、構想から約半年かけて実装した。何でも調べれば出てくる時代にはなったが、その情報源を蓄積・公開している先人たちには感謝したい。この記事も、機械学習Webアプリを作りたい誰かのヒントになればよいなと思う。
- 投稿日:2020-05-16T12:51:17+09:00
doc2vec・scikit-learn・Django・Vue.js・Herokuで機械学習webアプリを作った備忘録
はじめに
タイトルの通り、doc2vec・scikit-learn・Django・Vue.js・Herokuなどいろいろ駆使し、機械学習Webアプリケーションをフルスクラッチ実装した。
機械学習のモデリング手法、またはSPA構築のHowToはそれら単体では紹介されているが、それらをフルスクラッチで構成するノウハウは未だあまり出回っていないように思える。
まずは自分の備忘のため、そして特に作った機械学習モデルをWebアプリ化して公開してみたい人のため、アプリの構成や躓いたポイントなどを記事に残す。この記事のスコープ
含む内容
- Webアプリを実装するのに使用したライブラリ
- Webアプリのディレクトリ構成
- 機械学習モデルとDjangoの連携
- Vue.js、Django REST Frameworkを使用したSPA(Single Page Application)実装
- Herokuデプロイの設定Tips
含まない内容
- ライブラリ単体の(doc2vec, scikit-learn, ...)説明や、Web開発の基礎(フロントエンドやREST Framework)の説明。各種チュートリアルを参考にされたい。
- 自然言語処理・機械学習の理論の説明。筆者は未だ理解が浅く、理論に関する言及はなるべく控える。
- ソースコード。いつかGithubで公開するかも。
- アプリの精度に対する議論。そもそも文章から性格を判断すること自体ナンセンスだし、学習のためのジョークアプリという位置づけにしたい。
作ったWebアプリの紹介
URL
http://personalityestimator.herokuapp.com/サービスの説明
- 英文をInputとし、MBTIメソッドに基づいた16タイプの性格診断を行う。
- 16タイプの指標は、2値をもつ4つの指標の乗算(2^4 = 16)で表される。文章を入力することで、それぞれの指標にどれだけ寄っているかをパーセンテージで算出することができる。
- 試しにトランプ大統領のスピーチをInputするとENTP - The Debater(討論者)と評価される。なかなかそれっぽい。
参考:MBTI 4指標(MBTI協会サイトより引用)
指標 基準 興味関心の方向 外向(Extroverts) vs 内向(Introverts) ものの見方 感覚(Sensors) vs 直観(i Ntuitives) 判断のしかた 思考(Thinkers) vs 感情(Feelers) 外界への接し方 判断的態度(Perceivers)・知覚的態度(Judgers) システムの説明
- 教師データとしてKaggle公開のデータセット「(MBTI) Myers-Briggs Personality Type Dataset」を使用している。レコードの単位は被験者単位で、カラムは性格診断結果(Type)と投稿した文章(Posts)の二つを持つ。
- 学習は、投稿した文章(Posts)をdoc2vecで100次元ベクトル化し、それらに対して2値分類を行うモデル(ロジスティック回帰)を4つ実装している。
備忘録
ランタイム・仮想環境
Pythonバージョンは
python-3.7.3
を使用。仮想環境はanyenv + pyenv(インタプリタ切り替え) + virtualenv(パッケージ切り替え) + virtualenvwrapperを使用している。
尚、Anacondaは使用していない。当初入れていたがアプリ実装時はすべて削除している。(condaとpip:混ぜるな危険)ブループリント
当Webアプリのブループリント(構成図)を説明する
No. コンポーネント 説明 ① FE Vue.jsを採用。axiomライブラリを使用してAPIを非同期でコールし、返却値をレンダリングする。
CDN版を採用し、状態管理(vuex)やルーティング(vue-rooter)は実装していない。② API Django REST Frameworkを採用。フォームで入力した文章をリクエストし、モデルの予測結果をレスポンスする。 ③ DB SQ Liteを採用。プロジェクト開始時に自動で付属するだけで、今回特にデータの参照・登録は行っていない。 ④ Model Gensim (doc2vec)を単語のベクトル化、Scikit-Learnをモデリングに採用。モデルは各指標ごとに2値分類を行うモデルを4つ実装。 ⑤ Server Herokuを採用。①〜④を丸ごと1つのAppとしてデプロイしている。 requirements.txt
仮想環境にインストールした各種ライブラリを説明する(google-api-coreとか、明らかに不要そうなものも入っている気がする・・・)。基本すべてpipでインストール可能。
requirements.txtboto3==1.12.36 botocore==1.15.36 cachetools==4.0.0 certifi==2019.11.28 chardet==3.0.4 dj-database-url==0.5.0 Django==2.2.5 # ① django-heroku==0.3.1 # ② djangorestframework==3.10.3 # ① docutils==0.15.2 gensim==3.8.1 # ③ google-api-core==1.16.0 google-auth==1.13.1 google-cloud-core==1.3.0 google-cloud-storage==1.27.0 google-resumable-media==0.5.0 googleapis-common-protos==1.51.0 gunicorn==20.0.4 # ② idna==2.9 jmespath==0.9.5 joblib==0.14.1 numpy==1.18.1 pandas==1.0.1 protobuf==3.11.3 psycopg2==2.8.5 pyasn1==0.4.8 pyasn1-modules==0.2.8 python-dateutil==2.8.1 pytz==2019.3 requests==2.23.0 rsa==4.0 s3transfer==0.3.3 scikit-learn==0.22.2.post1 # ③ scipy==1.4.1 six==1.14.0 smart-open==1.10.0 sqlparse==0.3.1 urllib3==1.25.8 whitenoise==4.1.3①:Django関係のライブラリ
django
はWebフレームワーク、djangorestframework
はその中でもREST API実装特化。両方ともpipでインストールする。②:Heroku関係のライブラリ
djangoアプリをherokuにデプロイする際に必要となる。
django-heroku
をインストールすれば依存パッケージのwhitenoise
やdj-database-url
も一緒にインストールされる。③:機械学習関係のライブラリ
gensim
,scikit-learn
を導入する。モデルの学習はjupyterで別で学習しているが、モデルの予測処理には必要。他、numpy
,pandas
等も一緒に導入する。ディレクトリ構成
当Webアプリのディレクトリ構成を説明する。
personalityestimator ├── Procfile # ② ├── apiv1 # ① │ ├── __init__.py │ ├── __pycache__ │ ├── admin.py │ ├── apps.py │ ├── clfs ③ │ │ ├── logreg_ie.pickle │ │ ├── logreg_pj.pickle │ │ ├── logreg_sn.pickle │ │ ├── logreg_tf.pickle │ │ └── model.pickle │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── serializers.py │ ├── tests.py │ ├── urls.py │ └── views.py ├── config # ① │ ├── __init__.py │ ├── __pycache__ │ ├── local_settings.py # ④ │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── db.sqlite3 ├── get_random_secret_key.py # ④ ├── manage.py ├── mbti # ① │ ├── __init__.py │ ├── __pycache__ │ ├── admin.py │ ├── apps.py │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── 0002_..... │ │ ├── __init__.py │ │ └── __pycache__ │ ├── models.py │ ├── tests.py │ └── views.py ├── requirements.txt # ② ├── runtime.txt # ② ├── static │ └── style.css └── templates └── index.html①:django プロジェクト・アプリケーション
指定ファイルは以下のコマンドで生成している。
(venv) $ django-admin startproject config . (venv) $ python manage.py startapp mbti (venv) $ python manage.py startapp apiv11プロジェクト、2アプリケーション(mbti, apiv1)で構成する。
プロジェクト開始時、config .
と指定することで、ベースディレクトリと設定ディレクトリ(config)が同じ名前になることを回避している。アプリケーションはモデルのみを定義するmbti
, REST API機能を有するapiv1
の2つを作成している。
上記コマンド以外では、以下を手動で実行している。
apiv1/serializers.py
を追加。REST Framework上でのデータの保持を行う役割を持つ。バリデーション等もこのファイルで定義する。static
、templates
ディレクトリを追加し、静的ファイルやindex.htmlを格納する。settings.py
も同ディレクトリを検索するように一部書き換える。②:Herokuデプロイ設定
Herokuデプロイ時には、
Procfile
、requirements.txt
、runtime.txt
の3つを作成する。Procfile
はアプリを動かす指示書の役割、requirements.txt
は使用するライブラリをherokuに知らせる役割、runtime.txt
は使用するPythonのバージョンを知らせる役割を持つ。③:モデルの格納
学習済のgensim, doc2vecのモデルをpickle化し、
clfs
ディレクトリに格納している。
model.pickle
は単語のベクトル化、logreg_XX.pickle
はそれぞれの指標に対してロジスティック回帰で2値分類する。④:秘密情報の設定
次節のはまったポイント③を参照。
はまったポイント
①Procfileの設定によるHerokuデプロイエラー
問題
Herokuでデプロイには成功するが、WebアプリにアクセスするとApplication Errorが発生する。解決策
Procfileのプロジェクト名の記載欄に、間違えてルートディレクトリ名を記載していたことが原因だった。
上記コマンドstartproject config .
の通り、このWebアプリの正しいプロジェクト名はconfig
とである。一般的で紹介されているディレクトリ構成と異なっているためなかなか気づけなかった。(誤)web: gunicorn personalityestimator(ルートディレクトリ名).wsgi --log-file - (正)web: gunicorn config(設定ファイル名).wsgi --log-file -②index.html上のデリミタ「{{}}」がDjango, Vue.jsで重複する
問題
今回Vue.jsはCDN版を採用しているため、index.html
に<script>タグで直接Vue.jsを書き込んでいる。
Djangoテンプレートの変数表示構文とVue.jsのMustache構文が両方ともデリミタ「{{}}」が使用されているため、そのままの設定ではバッティングする。解決策
Vue.jsのデリミタを変更する。Vue.options.delimiters
でデリミタを「#{}」に変更して衝突を回避する。index.html<!DOCTYPE html> {% load static %} <html lang="en"> <head> <meta charset="UTF-8"> ... <title>PersonalityEstimator</title> <!-- CSS --> <link rel="stylesheet" href="https://unpkg.com/ress/dist/ress.min.css"> <link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet"> <link href="{% static 'style.css' %}" rel="stylesheet"> <!-- JS --> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <!-- axios --> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> </head> <body> <div id="app"> ... </div> </body> <script> Vue.options.delimiters = ['#{', '}'] // ポイント var app = new Vue({ el: '#app', data: { ... }, methods: { ... }) </script>③DjangoのSECRET_KEYをプロダクション環境に公開しないようにする
問題
settings.py
に初期値コメント「SECURITY WARNING: keep the secret key used in production secret!」の通り、SECRET_KEY
はプロダクション環境からは見えないようにしたい。解決策
settings.py
から新たにlocal_settings.py
を複製し、SECRET_KEY
はlocal_settings.py
のみに記載する。settings.py
のSECRET_KEY
はlocal_settings.py
からインポートする。settings.pyimport os import django_heroku from os import environ from socket import gethostname # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! HOSTNAME = gethostname() if 'local' in HOSTNAME: from . import local_settings SECRET_KEY = local_settings.SECRET_KEY else: SECRET_KEY = environ['SECRET_KEY'] # SECURITY WARNING: don't run with debug turned on in production! DEBUG = False ALLOWED_HOSTS = ['127.0.0.1', '.herokuapp.com'] ...
local_settings.py
は.gitignore
に記載しgit管理されないようにする。
DEBUG = False
に書き換えるのも忘れないように。尚、上記ディレクトリ構成にあった
get_random_secret_key.py
は新しくSECRET_KEY
を生成する際に使用した。一度うっかり秘密鍵をgit管理に上げてしまったので、鍵の再生成を行った。get_random_secret_key.pyfrom django.core.management.utils import get_random_secret_key secret_key = get_random_secret_key() text = 'SECRET_KEY = \'{0}\''.format(secret_key) print(text)④その他
django-heroku
のインストール時に同梱されるwhitenoise
は最新バージョンで5系になっている。最新の情報が載っている参考サイトでもほぼ4系を採用していたため、アンインストールした後再度4系をインストールした。- CSS。拡大・縮小による表示崩れやレスポンシブ対応の工夫をしている。親構造に
max-width
を指定するwrapperクラスをあちこちで指定している。まだ嵌ってるポイント・Todo
本アプリのWebアプリの残課題を記載する。解決策をご存知の方がいらっしゃればコメントをいただきたい。
- index.htmlに記載されている<script>をjsファイルに分離し、staticに格納したい。main.jsファイルを読み込む手法も検証したが、どうやっても正常に読み込まれず断念。
- clsf(モデル)の格納場所を変えたい。何となくapiv1の中ではなくstaticの中に置くべきな気がしているが、あるべきが何かを知りたい。
- apiv1/view.pyをリファクタリングしたい。Typeの設定("INTJ": "The Architect"など)は同ファイルにベタ書きで持っているので、モデルに移植してマスタテーブル化したい。が、2つのModelを参照してレスポンスする方法がよくわからず断念。
- Modelの精度は上げたい。次は深層学習にチャレンジするつもり。
参考にしたサイト・書籍
①:(Web)doc2vec and logistic regression
URL
https://www.kaggle.com/wpncrh/doc2vec-and-logistic-regression説明
当アプリで使用するデータセットを使用したKaggleのKernel。
Doc2Vec
による単語のベクトル化や、前処理の方法はこのKernelを参考にしている。本アプリではこのKernelに実装されている前処理に加えて、URLや記号を正規表現で取り除いている。②:(動画)Build a Machine Learning API with Django
URL
https://youtu.be/tDnAcbYROSI説明
Django REST FrameworkとMachine Learningをかけ合わせたアプリ実装を全6回で説明している。範囲はモデル実装からDjangoアプリ作成、Herokuにデプロイするところまですべて。
モデルをPickle化してDjangoアプリ内に入れるアイデアはこの動画から着想を得た。一方、Django REST Frameworkの記法は若干怪しいように見受けられるので、Djangoの学習はチュートリアルに沿うことをおすすめする。後半のHerokuデプロイは観ていない。
全編インド人による英語の講義。③:(書籍)現場で使えるDjangoの教科書
URL
現場で使える Django の教科書《基礎編》
https://booth.pm/ja/items/1308742現場で使える Django REST Framework の教科書
https://booth.pm/ja/items/1559869説明
Django及びDjango REST Frameworkを体系的に学ぶには最もおすすめ。
Webアプリのディレクトリ構成や、DjangoとVue.jsの連携、デリミタの重複回避はこの書籍を参考にした。特にDjangoとVue.jsの連携はサンプルプロジェクトがそのまま載っているので大変参考になる。④(Web)『完全版』Djangoアプリをherokuにデプロイ!
URL
http://digital-tree.xyz/blogs/1169説明
DjangoアプリケーションをHerokuにデプロイする手順が記載されている。
2019年9月の記事のため(2020年5月現在は)、比較的最新。⑤(Web)Djangoでの"秘密にしたい値"の取り扱い - ティッシュ残り一枚
URL
https://tsukachu.hatenablog.com/entry/handling_secret_keys説明
Heroku、Github等で秘密鍵を公開しないようにするための実装方法の記載がある。
嵌ったポイント③「DjangoのSECRET_KEYをプロダクション環境に公開しないようにする」は本記事を参考にしている。⑥(書籍)1冊ですべて身につくHTML & CSSとWebデザイン入門講座
URL
https://www.amazon.co.jp/dp/4797398892/ref=cm_sw_em_r_mt_dp_U_Of2VEbSY2RKCE説明
HTMLとCSSの説明。
アプリ構想時点でCSSが全く分からなかったのでこの書籍で1から学習した。スマホ・PC両対応したレスポンシブデザインを作るのにも参考にしている。⑦その他
Python自体はPythonデータサイエンスハンドブックや、みんなのPython 第4版で学習した。
終わりに
筆者はエンジニアではなく、趣味で一人コードを書いている。このアプリも空き時間を使って、構想から約半年かけて実装した。何でも調べれば出てくる時代にはなったが、その情報源を蓄積・公開している先人たちには感謝したい。この記事も、機械学習Webアプリを作りたい誰かのヒントになればよいなと思う。
- 投稿日:2020-05-16T09:28:18+09:00
Docker×Laravel×Vue (Laravel部分)
こちら側ではタイトルにあるように
Docker×Laravel×Vue 開発における
(Laravel部分)のお話をしていきます。SPA認証
Laravel Airlock -> Sanctumに改名!!
これでは実装できなかったので諦めてLaravelのweb版で対応することにしました。
マルチ認証
この記事に死ぬほどお世話になりました!!
https://qiita.com/namizatop/items/5d56d96d4c255a0e3a87?utm_campaign=popular_items&utm_medium=feed&utm_source=popular_items#controllerRouteServiceProviderの値でlogin後の挙動が変わることは初知りでした!!
Auth::routeって??
middlewareの認証されてるかされてないか
blade.php@guest('admin') //認証されていない場合表示させるもの!! @endguestblade.php@auth('admin') //認証されてる場合表示させるもの @endauthでadminのmiddleware側の認証の有無が確認できます。
https://readouble.com/laravel/5.5/ja/blade.html
Middleware
https://tech-blog.optim.co.jp/entry/2019/08/13/173000
Class消してるのに Cannot declare class Illuminate\Support\Facades\App\User, because the name is already in use が出てくる
composer dump-autoloadで対応!!
https://qiita.com/WebSysRider/items/e41f211f8c913e008d03
バリデーション
Requestクラス説明
https://www.ritolab.com/entry/41https://www.ritolab.com/entry/40#aj_3
ルーティングで名前指定した時にどうやって値渡す??
{{ route('user.profile', ['id' => 1]) }}こんな感じで第一引数にルーティング名指定して上げて、第二引数で連想配列で値を渡してあげるみたいです!!
これでパラメータ指定してURL渡せそうです!!https://qiita.com/kazuhei/items/935257b0d72fa314d461
フォームリクエスト
Controller内にValidationロジックを書くのは保守運用上あまり良くない。
→Requestクラス内に切り出してあげる。その際に出た
This action is unauthorizedpublic function authorize() { return false; }を
public function authorize() { return true; }に変更することで対応完了!!
https://nekorokkekun.hatenablog.com/entry/2019/07/13/223834
登録画面
// 入力画面post時 public function postIndex() { // postデータ取得 $data = Request::all(); // エラーチェックなどの処理 // 確認画面へリダイレクト return redirect('/form/confirm')->withInput(); } // 確認画面 public function getConfirm() { // post内容を取得 $postdata = Session::get('_old_input'); return view('form.confirm', compact('postdata')); }http://cly7796.net/wp/php/take-over-the-value-when-you-redirect-in-laravel-of-form/
$validationCode = request()->session()->get('validation_code', '');組み合わせで前ページの値持ってける。
Routing書くの面倒なんでグルーピング
middleware ・・・ ミドルウェアでグループ化し適用する namespace ・・・ ネームスペースでグループ化 domain ・・・ サブドメインをグループ化 prefix ・・・ URLが始まる文字列でグループ化 name ・・・ ルーティング名でグループ化ブログから拝借しましたが→これで対応できそうです。
https://blog.capilano-fw.com/?p=556
エラー関係
TOO Large
自分の場合localのphp.iniの設定ファイルと同じようにdocker内のphpが読みこまれていたのでローカルの
php.iniを変更して対応しました。https://qiita.com/kangyoosam/items/609b6eb1a262dee9f547
ファイルアップロードが失敗する場合
https://qiita.com/sano1202/items/b2babd55a6b11109de9a
Laravel ファイルがアップロードできない
まじか!!!!
調子に乗ってupload_max_filesizeを1024Mにしたのが原因でした。。。
アップロードできるサイズに直接関係するのは「upload_max_filesize」と「memory_limit」です。
「memory_limit」は「upload_max_filesize」よりも大きい値を設定するようにします。upload_max_filesize > memory_limit になったらエラーになる!!
https://gray-code.com/php/setting-for-file-upload-by-phpini/
シンボリックリンク
php artisan strage:linkで作ることができるリンク
publicからファイルを取得するのに使うんやけど
アップロードされたファイルは基本Storageに入ってくるからここにアクセスするためのコマンド。storage/ap/public
から触れる。src ="{{asset('/storage/company/description/first/'.$companyDescription["img_1"])}}"みたいに自分はアクセスした。
認可
自分が投稿した記事しか編集できないようにする。
https://tech.windii.jp/backend/laravel/authorization-basic画面
Flash Message
https://qiita.com/usaginooheso/items/6a99e565f16de2f9ddf7
ページネーション
なんとか対応完了
https://qiita.com/rorensu2236/items/abf5706f56a124e50640
Eloquentの検索結果がからかどうか判定するメソッド
if($blogs->isEmpty()){ //なんらかの処理 } if($blogs->first()){ //なんらかの処理 }403 This Action is unauthorized
この画面になった時は大概 Requestクラス内の
public function authorize() { return true; }になっていない可能性を疑う。
全部自分の場合はこれでした。