Electron+react+django REST framework
Local GUIアプリを作成する必要が出た際、言語の候補としては C#,python,Java などが上がってくることと思います。ただし、GUIの見た目がほぼWindows95時代のアプリのごとくいけていない。。。
そこでFrontをreactで、BackendをDjangoRESTFramework で実装しElectronを使ってdesktop app 化することにしました。
情報が少なく、苦労したので、個人メモがわりに残しておきます。
参考にさせていただいたサイト:
① [Wijmo(ウィジモ)」とElectron、Reactを組み合わせて、Web技術でデスクトップアプリをつくろう] (https://codezine.jp/article/detail/13182)
② Reactアプリから Django Rest API を叩いてみる
方針:
- 最初にElectron+React でLocal GUI アプリを作成する(上記①)
- 次にDjango REST Framework を導入してAPIのend point を作成する(上記②)
- electron 起動時にpython-shell を使って、django server を立ち上げる
- フロントからhttp通信を使ってデータを取得する
方針1、2
基本的には①のサイトの流れに沿ってreact,electron のGUIアプリを作成していきます。
上記サイトに沿って作成すれば問題なく作成できると思いますし、コードを無断転載するのもよくないと思い詳細は載せません。
react+electron でGUIアプリが起動することが確認できたら、そこに②のサイトを参考にしながらDjango REST framework を導入します。
こちらも基本的に②のサイトに沿ってDjangoREST framework を導入していきます。
最終的なファイル構造は以下のようになっているはずです。
react-electron-django
|
|- django
| |- db.sqlite3
| |- manage.py
| |- djangoMain
| |_ djangoApp
|-- frontend
| |-public
| | |-electron.js
| | |- preload.js
| |-src
| |-App.tsx
|-index
#3 electron 起動時にpython-shell を使って、django server を立ち上げる
この時点でDjangoAPIの作成ができており、electron+react のアプリもできている状態です。
ここから問題となったのは
electronを立ち上げる際にどうやって同時にdjango serverを立ち上げて、electron が終了する際にdjango serverも終了するか
でした。
djangoのlocal server さえ立ち上げてしまえば、後はFront からaxiosなどでAPIを叩くだけです。
方針としては、electron.js の中でpython-shell を使って command python manage.py runserver localhost:8000
を叩けば良いのですが、その方法がわからず苦労しました。
結論といたしまして、まず上記のelectron.js の中で
//pythonShell のプロセスを後でkill するためにglobal 変数を設けている
let subpy;
//アプリケーションが起動可能になったらcreateWindowを呼び出す
app.on("ready", () => {
createWindow()
// Django 側のサーバーを立てるコマンド
subpy=PythonShell.run(`${path.join(__dirname, "../../django/manage.py")}`, null, function (err, result) { // exe:'./resources/app/app.py' edit: './app.py'
if (err) throw err;
console.log(result);
});
});
でpython manage.py
のコマンドを実行します。
(この際、後にelectron を閉じる時にdjango process をkill するためにGlobal変数にプロセスを格納しておきます。)
python manage.py
だけではサーバーは起動しません。 この後にrunserver を繋げたいのですが、、、、その方法がどうしてもわからず(ご存知の方は教えて下さい!)、結局 manage.py file にある関数execute_from_command_line(sys.argv)
のsys.argvのところに直接"runserver"を入れることで解決しました。
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangotodo.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
# execute_from_command_line(sys.argv)
//書き換えたところ
execute_from_command_line(['',"runserver"])
if __name__ == '__main__':
main()
これでelectron を立ち上げた際に同時にdjango server も立ち上がるはずです。
最後にelectron を終了したときに同時にdjango server も閉じるように以下を書き加えます。
//終了時に子プロセスとその子孫を終了させる
app.on("quit", () => {
// ここを追加!!
// pythonShellをkill
subpy.childProcess.kill('SIGINT');
pids.forEach((pid) => {
try {
process.kill(pid);
} catch (e) {
console.log(e);
}
});
});
4 front からHttp通信でデータを取得
3のプロセスが終われば、あとはフロントからAPI通信でデータを取得するだけです。
import axios from "axios";
import React, {useState} from "react"
function App() {
const [message, setMessage] = useState("top secret")
const sendMessage = async ()=>{
const returnMessage = await axios.get('http://localhost:8000/api/').then((res)=>{
return res.data
})
setMessage(returnMessage)
}
return (
<div>
<button onClick={sendMessage}>
テストメッセージ送信
</button>
<h1>
{message}
</h1>
</div>
);
}
export default App;
##最後に
react,electron,flask を使った記事はいくつか拝見させてもらったのですが、djangoREST framework を使った記事は少なくて苦労したので、どなたかの参考になれば幸いです。