docker nginxの基本的な使い方
dockerを触ってみて分かったこと。
dockerのコマンドを使ってimage作成やコンテナを実行する。 これとは別に、つまりdockerコマンドを使ってimage作成する代わりに、Dockerfileを作ってdocker buildコマンドを使うとimageを作成する事もできる。 ここに関して当初自分はDockerfileにはコンテナの起動に関する内容を記述できるものだと勘違いしていた。しかしDockerfileはどんなimageを作成するかを明文化するだけである。
docker build -t (イメージ名:タグ) (Dockerfileがあるディレクトリ)
これでimageを作成する事ができる。
そしてこのイメージを使ってコンテナを起動するわけだけれども、docker-compose.ymlの記述に従って作成したimageやダウンロードしたimageをコンテナとして起動することができると分かった。したがってdocker-composeでできることをdockerfileではどのように表現できるのかと考えだしたら当然できないことなので時間を無駄にしてしまう。。。
docker hubのnginx
https://hub.docker.com/_/nginx
Alpine Linux 対応 Nginx イメージのダウンロード
# docker pull nginx:alpine
Nginxコンテナの実行
# docker run -d -p 8080:80 nginx:alpine
これはホストの8080番ポートにアクセスすると80番ポートに渡される。
dockerfileで書くとどうなるか
FROM nginx:1.15.12-alpine COPY nginx.conf /etc/nginx/conf.d
#./nginx.conf server { listen 80; server_name local_host; location /static { alias /usr/share/nginx/html/static; } location /media { alias /usr/share/nginx/html/media; } location / { proxy_pass http://127.0.0.1:8000; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; proxy_set_header X-Forwarded-Proto $scheme; } }
dockerfileからimageを作成する
docker build -t myNginx:hoge .
コンテナを起動する
docker run myNginx:hoge
django vueを追加する
MPAでvueを使いたい。。。
色んな方法で実現できると分かった。
最終的にはvue cliを使って構築するのがわかりやすいと感じた。cdnはもちろんかんたんだけれどもvuetifyを組み合わせて使う方法が全然わからなかった。
vue cliを使わない方法を試してみたのでそのメモを記す。 ファイルの構成を以下のようなりわかりやすいと感じた。
PROJECT - assets - django-project - node_modules - package-lock.json - package.json - webpack-stats.json - webpack.config.js
仕組みは ./node_modules/.bin/webpack --config webpack.config.jsを実行するとwebpack-stats.jsonがPROJECTのディレクトリに生成される。このファイルをdjango-webpack-loaderが読み込みvueが表示される仕組み。
webpackについてはこれを見ればわかる。 https://qiita.com/soarflat/items/28bf799f7e0335b68186:totle
webpack.config.jsはwebpackの設定ファイル。 エントリーポイントや、ファイルの出力場所、プラグインなどを設定することができます。
モジュール化するためにjavascriptで
export default function
を使うようだ。 それについてはここに詳しく書いてある. ES6のexportについて詳しく調べた - Qiita
webpackコマンドはnode_modules/.bin/webpackに実行ファイルがあるので別にパスを通さなくてもこれで実行すれば良い。
webpackのメリット
- 機能ごとにファイルを分割(モジュール化)する開発ができる
- 自分が作成したモジュールだけでなく、外部モジュール(npmなどでインストールできるパッケージvuetifyなど)も利用できる
- リクエスト数を減らせる
- 依存関係を解決したファイルを出力できる
外部モジュールを利用するときはどのようにすれば利用できるのか...
npmにインストールする。
npm install jquery --save
そしてmain.js(エントリポイントでimportすれば良い)
import $ from 'jquery';
参考記事: django-webpack-loader のセットアップ - Qiita
Vue cliを使ってMPAを実現する
webpackのみでdjangoとvueを統合する場合はwebpack.config.jsでcss関係の調整が必要で知識が必要になる。 これは自分で調整するために行うので別途知識を補充する必要がある。
一方vue cliを使う方法はvue cliが色々なパッケージの調整をしてくれるのでcssについて考える必要がなくてなんとか環境を構築することができた。
Vue CLI は、アプリケーションの構築の複雑さを抽象化するために作られた次世代の cli ツールです。Vue CLI でアプリを起動すると、公式の WebPack の更新や構成の変更、Vuetify の更新を困難なアップグレードプロセスなしで取得することもできます。
環境構築方法をメモしておく。
前提: - vuetifyを導入する - django-webpack-loaderを使って構築する
環境
Django==2.2.6 django-webpack-loader==0.7.0 webpack-bundle-tracker@0.4.3 vue/cli@4.4.6
最初にdjangoのインストール
pip install django
プロジェクトの作成
django-admin startproject myproject cd myproject
以下を入力してプロジェクトの起動
python manage.py runserver
http://127.0.0.1:8000ここにアクセスして以下が表示されればココまではおっけい。
djangonのプロジェクトテンプレート準備する
- settings.pyにおいてテンプレートディレクトリを定めること
- テンプレートを作成する
- urls.pyでテンプレートを表示させる設定を行う
#myproject/myproject/settings.py #以下を追加 TEMPLATES_DIR = os.path.join(BASE_DIR, 'templates') #DIRSにTEMPLATES_DIRを加える TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [TEMPLATES_DIR,], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]
テンプレートを作成する。
# myproject/templates/application.html <h2>ああああああ</h2>
urls.pyのセッティング
#myproject/myproject/urls.py from django.contrib import admin from django.urls import path from django.views.generic import TemplateView urlpatterns = [ path('admin/', admin.site.urls), path("", TemplateView.as_view(template_name="application.html"), name="app", ), ]
ここまでは通常のdjangoのプロジェクトを作っていく流れです。ここからvue cliを使ってvueのプロジェクトを作成していきます。
pip install django-webpack-loader==0.7.0
#myproject/myproject/settings.py #以下を追加する FRONTEND_DIR = os.path.join(BASE_DIR, 'frontend') WEBPACK_LOADER = { 'DEFAULT': { 'CACHE': DEBUG, 'BUNDLE_DIR_NAME': '/bundles/', #最後にスラッシュを忘れないこと 'STATS_FILE': os.path.join(FRONTEND_DIR, 'webpack-stats.json'), } } INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'webpack_loader', #これを追加 ]
settings.pyに記述したwebpack_loaderやWEBPACK_LOADERはdjango-webpack-loaderに関するものである。
INSTALLED_APPSでdjango-webpack-loaderを有効にする。
WEBPACK_LOADERの'STATS_FILE'でwebpack-stats.jsonを読み込むパスを定める。webpack-stats.jsonはバンドル化したファイルに関連するファイルで、これを通じてバンドル化したファイルを読み込むのだろうと推測している。詳しくはまだ調べきれていない。
次にvueのプロジェクトを作成する。
npm install -g @vue/cli
vue --version @vue/cli 4.4.6
vue create frontend
vuetifyをvue cliを使ってプロジェクトに加える。この方法を使うとwebpackのみで構築する方法と違ってwebpack.config.jsを自分でいじる必要がなくなるのでハマるリスク回避できる。webpackのみでハマったのでこれはありがたいです。
cd frontend vue add vuetify
関連するパッケージをインストールする。
npm install
このバージョンをインストールしないと後々DJANGO側でエラーが出てしまい困ることになるので重要。
npm install --save-dev webpack-bundle-tracker@0.4.3
npm run serve
下のように表示されればおっけい
vue.config.jsを編集する。
const BundleTracker = require("webpack-bundle-tracker"); module.exports = { publicPath: "http://127.0.0.1:8080/", outputDir: './dist/', chainWebpack: config => { config.optimization .splitChunks(false) config .plugin('BundleTracker') .use(BundleTracker, [{filename: '../frontend/webpack-stats.json'}]) config.resolve.alias .set('__STATIC__', 'static') config.devServer .public('http://0.0.0.0:8080') .host('0.0.0.0') .port(8080) .hotOnly(true) .watchOptions({poll: 1000}) .https(false) .headers({"Access-Control-Allow-Origin": ["\*"]}) } };
cd frontend npm run serve
python manage.py runserver
これでdjangoのテンプレートとvueを統合することができた。
次に各エンドポイントに応じてテンプレートを変更することを実現させる。これはもちろん使用されるテンプレートに応じてvueを使い分けるということである。
これはvue.config.jsを修正すれば良い。module.exportsにpagesを加えれば良い。またpagesの値を定める。
const BundleTracker = require("webpack-bundle-tracker"); //追加事項 const pages = { 'vue_app_01': { entry: './src/main.js', chunks: ['chunk-vendors'] }, 'vue_app_02': { entry: './src/main2.js', chunks: ['chunk-vendors'] }, } module.exports = { pages: pages, //これを追加 publicPath: "http://127.0.0.1:8080/", outputDir: './dist/', ... ... }
次に./src/main2.jsを作成する。これは例として以下のようなファイルとする。
import Vue from 'vue' import App2 from './App2.vue' #後でファイルを作成する import vuetify from './plugins/vuetify'; Vue.config.productionTip = false Vue.config.delimiters = ["[[", "]]"]; new Vue({ vuetify, render: h => h(App2) }).$mount('#app')
App2.vueの作成
cd src touch App2.vue
<template> <v-app> <v-app-bar app color="primary" dark > <div class="d-flex align-center"> <v-img alt="Vuetify Logo" class="shrink mr-2" contain src="https://cdn.vuetifyjs.com/images/logos/vuetify-logo-dark.png" transition="scale-transition" width="40" /> <v-img alt="Vuetify Name" class="shrink mt-1 hidden-sm-and-down" contain min-width="100" src="https://cdn.vuetifyjs.com/images/logos/vuetify-name-dark.png" width="100" /> </div> <v-spacer></v-spacer> <v-btn href="https://github.com/vuetifyjs/vuetify/releases/latest" target="_blank" text > <span class="mr-2">Latest Release</span> <v-icon>mdi-open-in-new</v-icon> </v-btn> </v-app-bar> <v-content> <HelloWorld/> </v-content> </v-app> </template> <script> import HelloWorld from './components/HelloWorld'; export default { name: 'App', components: { HelloWorld, }, data: () => ({ // }), }; </script>
次に必要なdjangoプロジェクトのテンプレートを調整する
urlpatterns = [ path('admin/', admin.site.urls), path("", TemplateView.as_view(template_name="application.html"), name="app",), #以下を追加する path("test/", TemplateView.as_view(template_name="test.html"), name="app",), ]
touch templates/test.html
{% load render_bundle from webpack_loader %} <div id="app"> </div> vue_app_02 {% render_bundle 'chunk-vendors' %} {% render_bundle 'vue_app_02' %}
これでテンプレートによって別のvueを使うことができるようになる。
参考: Integrating Django and VueJs with Vue CLI 3 and Webpack Loader
constants.pyを設けるメリット
djangoでconstants.pyを設けるメリット
views.pyやurls.pyまたテストにおいてハードコーディングが少なくなる。 urls.pyにおいてviewネームを変更するとviews.pyの該当するreversやreverse_lazyのハードコーディング部分を探して変更する必要が出てくる。 しかし定数(変数)を定めておけば、urls.pyのビューネームを変更する。->constants.pyで該当変数を変更するだけで済む。
vue.jsのメモ その2
データバインディングとは
データと描画を同期する仕組み
データバインディングの種類
テキストのバインディング
テキストのバインディングの場合には{{}}で描画に反映するけれども、タグ内の属性値をいじる場合には{{}}で操作しない。 その際はv-bindとかそういった類を使うことを現状推測している。
htmlタグの属性値をバインディング
v-bindはhtmlのタグ内の属性値を定める働きがある。例えばdivタグの属性classの内容に属性値としてcontainerをセットしたいとする。
つまり以下のようにしたい。
<div class="container"></div>
これはvueを使うと以下のように実装する事ができる.
<div v-bind:class="base"></div> new Vue({ data:{base:"container"} })
v-modelを使うのは双方向データバインディングをためっていう認識で正しいのか? --> 正しい。 双方向データバインディングを実現するためにv-modelディレクティブを使う。
双方向データバインディングには種類があると思われる。
v-modelディレクティブは2つの処理を一つにまとめているだけである。その処理は、
HTTPクライアント機能を実装する
vueではaxiosが推奨されている事はわかった。
axios を利用した API の使用 — Vue.js
クライアントを実装する方法をまとめる前に何の要素が必要になるか予め想像してみる。
axiosのソースをどうするか
どうやってaxiosをインストールするか。cdnがあるか?
クライアントを作成する際にどんな情報が必要になりそうか
httpクライアントであれば、
クライアントインスタンスを作成して、HTTPのメソッドを設定して、endpointを設定すればレスポンスが返ると想像する。 あとはHTTPリクエストのヘッダーのContent-Typeにtext/htmlかtext/jsonかを設定する場合も必要なのかもしれない。
クライアントインスタンスを生成するためのクラスは何なのかも調べる必要だと思う。
レスポンスの解析方法も分かったらメモに残しておく。
axiosのcdnがあったのでcdnを使ってみる方法を採用した。
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.js"></script>
cssを反映させる方法
cssを反映させるにはclassの値を設定する方法とstyleの値を設定する方法がある。 どちらも属性値の設定なのでv-bindを使ってやっていく。
<p v-bind:class="{bigSize: isBigSize}" ></p>
イベント疑問点
メソッドにeventとかeを引数にとることができるけどこれは何なのか?
イベントをconsole.logで中身を見てみると、イベントに関連した情報が格納されていることがわかる。 例えばイベントが起きたtagやラベルなどを取得する事ができる。
コンポーネント
コンポーネントとはページを構成するUI部品の役割を担うVueインスタンスらしい。
コンポーネントは再利用可能であること、そしてメンテナンス性を高める事ができることがメリットである。
コンポーネントの登録はグローバルで使用できるように登録する方法とローカルで使用できるようにする登録方法がある。
グローバルで登録するためには以下のようにVueクラスメソッドを使用する。 コンポーネントを利用するにはコンポーネント用のメソッドを使う必要がある。
Vue.component("コンポーネント名",{template:"<p>Hello</p>"})
定義したコンポーネントをどのようにhtmlで使うのか。
それはVue.componentとして定義したコンポーネント名をhtmlのタグ名として使用する事ができる。
<コンポーネント名></コンポーネント名>
またコンポーネントのローカル登録という概念がある。これはスコープを定めてそのスコープ内だけでしか使えないみたいなイメージだ。まあつまりローカル
var helloComponent = {template:"<p>Hello Vue.js</p>"} var Vue({ el = "#app", components :{ "myComp" : hello-Component } })
コンポーネント名の命名にも決まりがあるようでコンポーネントにはハイフンを加える必要がある。 またコンポーネントのdataプロパティは関数である必要もあるらしい。
VueRouterについて
VueRouterはシングルページアプリケーション(SPA)を作成するためのルーティングライブラリ。https://router.vuejs.org/ja/
シングルアプリケーションにおけるページ遷移の機能を担うライブラリ。
VueCLIでできること
- プロジェクトの雛形を作成
- 複数のjsファイルを一つにまとめる
- .vueファイルをjsに変換する
- トランスパイル
- javascriptの静的構文のチェック
- テストツールの導入
vue cli を使ってプロジェクトを開始する
Node.jsを使うことがvue cliを使う前提となっている。
Node..jsをインストールすることでnpmも付随してインストールできる。
これはNode Packgage Managerと呼ばれ、centosのyumに相当するものである。
vueのプロジェクト始め方(vue-cliを使って) - diadia
単一ファイルコンポーネントについて
単一ファイルコンポーネントは.vueを拡張子として作成する。 いろんなやり方があると思うけどそのベストプラクティスが知りたい。
単一ファイルコンポーネントはそのままではブラウザ表示する事ができない。したがってビルドする必要がある。 ビルドはwebpackとvue loaderで実施される。
単一ファイルコンポーネントの作り方
単一ファイルコンポーネントは.vueという拡張子を用いて作成する。中身はhtml, css, javascriptを書く。あと知りたいことは、単一ファイルコンポーネントであることをファイルに宣言する可能性があるのでそれをメモしたい。あとはどうやってビルドするのかも知っておきたい。
多分ビルドに関してはserveと同じ要領で
npn run build
でいけるんじゃないかっていう気はしている。 vueのプロジェクト内ではどのフォルダに単一ファイルコンポーネントを書くのかもはっきりさせたい。怪しいところはsrc/componentsに作成するのかなって思う。この予測は当たり。単一ファイルコンポーネントはsrc/components以下に作成する。
書き方の決まりがあった。 最初にtemplateタグを書く。その中でdivやpを記述するルールが有る。javascriptを書く場合にはscriptタグ内に記述すれば良い。特に新しいことはない。
<template> <div> <h1>Hello Vue.js</h1> </div>view </template> <script></script> <style scoped></style>
どうやって使うかって問題だけど作成した単一ファイルコンポーネントをhtmlにインポートして使うって感じである。
あとはhtmlに作成したテンプレートを記述する。これはファイル名を記述するだけでよい。
おそらくdjangoのurls.pyがrouterディレクトリの役割を果たし、viewsには表示するテンプレートを記述する感じだと思う。この中に単一ファイルコンポーネントを追加していく。その際にインポートと自作テンプレート名のタグを挿入する。って使い方だと思うけど、まだ理解できていない。
それにvue cliを使ってdjangoのプロジェクトを公開するのかも分かっていない。djangoのプロジェクトと抱き合わせた場合のvueの公開方法を調べる必要があるし、他にvue cli はSPAだけを作成するためのものなのかもはっきりしていない。他のソフトウェアとのつながりからどうなっているのか確認したい。
ビルドに関してはconfig.jsを変更したときに
npm run build
を実行するようだ。
webpackというものを使っているようだけれども、これは3種類のファイルが必要なようだ。
バンドルするファイル(統合対象のファイル)、エントリーポイントファイル、webpack設定ファイルである。
それぞれの役割を明らかにするのは重要か?とりあえずVue.jsは自動的に各ファイルを生成してくれるってことを聞いたけどその認識であっているのか?
そもそもwebアプリをSPAにするかMPAにするかでVueの使い方が大きく変わる。
ここの内容が大いに参考になった。
迷わないVueの学び方 - やわらかVue.js
axiosのpostメソッドはどうやって書くのか。
GitHub - axios/axios: Promise based HTTP client for the browser and node.js
ドキュメントによるとaxios.post(URL, {key:value})でかけるようだ。javascriptの引数の書き方としてオプション的なものは連想配列で渡すっていう特徴があるのかなと感じた。leafletでもこんな書き方してるし。
django等でform内にボタンを2つ設けたい場合がある。ここでbuttonやinputを使うとボタンやインプットタグの属性値を分岐処理のキーとして分岐させることになる。単純にonclickイベントを使いたい場合にはアンカータグにv-on:clickを使うことができた。bootstrapを使えばアンカータグであるものの見かけはボタンとして見えるのでこれは都合が良い方法ではないか?と思うがなにか問題点はないのか。。。
MPAにおけるvueの実装方法について
djangoのようなMPAではvue cliを使うような方法でvueを利用するのではなく、cdnを通じてvueを利用する。
このような文章を読んだのでそんなものかと思ってcdnでvueを実装してきた。ここまでは何も問題がなかった。
問題はvuetifyを使おうと思ったときだ。どのように利用するのか全くわからなかった。 vue cliを使えばできるみたいだけれども、
vue cliを使わない方法がcdnであるはずでここで困った。
よく調べてみるとMPAでもvue cliを使う方法があるようだ。今回はこれを試して実際に動かすことができたか検証する。
djangoのテンプレートシステムを使う場合scriptタグを使ってvueを使うことになるのでvueの単一ファイルコンポーネントを使うことができない。restframeworkをバックにvueを使うとdjangoのテンプレートシステムのメリットを享受できない。
MPAではcdnを使うことを示す資料
flaskやrailsとどう組み合わせるのか - やわらかVue.js
MPAでもvue cliを使えるよって資料
Vue CLI 3でSPAではなくMPA(複数エントリーポイント)のプロジェクトを作成する - Qiita
重要なツール: django-webpack-loader
https://cli.vuejs.org/guide/html-and-static-assets.html#building-a-multi-page-app
vueのプロジェクトをスタートさせる。vue cliで。そして設定はデフォルトを選択してプロジェクトを作れば良い。
わからん時っていうのは何がわからんのか?ファイルとファイルの関係性が分かってないんじゃないか?各ファイルの役割もわかることが重要だけれども関係性も分かっていないとだめなのかも。
もしかしてwebpack.config.jsに基づいてwebpack-stats.jsonが作られる関係が存在する?? webpackの設定ファイル=webpack.config.js
webpack.config.jsに書く重要な要素としてentryとoutputがある。ここで設定したファイルパスは必要なら自分でディレクトリを作成する必要になる。
コンパイルを行うときは
./node_modules/.bin/webpack
assets/bundlesにバンドルされたファイルができる。
これはwebpack.config.jsのアウトプットに記述された部分。
コンパイルを行う方法は
./node_modules/.bin/webpack
そしてコンパイル後に生成されるファイルがどこに出力されるかは、webpack.config.jsに記述しておくもの。具体的にはoutputという項にパスを記述する。 outputには出力されるファイルパスの他に任意のファイル名をアウトプットファイルとして設定できる。
django-webpack-loaderの仕様 使う際にはloadする。以下のように。
{% load render_bundle from webpack_loader %} {% verbatim %} <div id="app"> {{ message }} </div> {% endverbatim %} {% render_bundle 'main' %}
{% render_bundle 'main' %}はエントリのファイルが読み込まれるってこと??
vue cli4とvue cli3で変更点があることが分かった。vue.config.jsには以前はbaseUrlが使えるようだが、cli4ではこれが使えないことが分かった。
module.exports = { baseUrl: "http://0.0.0.0:8080/",
module.exports = { publicPath: "http://0.0.0.0:8080/",
代わりにpublicPathを使うようだ。
vue init とvue createはprojectを作成するときに実行するものらしい。
npmでバージョンを指定してパッケージをイントールする方法
バージョンを指定してパッケージをインストールする場合、パッケージ名の後ろに「@バージョン」を追記する。
npm install webpack-bundle-tracker@0.4.3
npmでパッケージの特定のバージョンをインストールする - Qiita
vuexについて
データフローを管理する目的らしい。
データをstoreに保存し、必要に応じて更新取得を行っていく仕組み。
templateでstoreのデータを取得する場合
{{ $store.state }}
アクション | Vuex アクションは store.dispatch がトリガーとなって実行される。したがってstore.dispatchはユーザー側のロジックに近いところで書くことが想定される。 これはtemplateで書くときとscript内で書くときで違いがあるか?また、どのように呼び出すかサンプルもほしい。
const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context) { context.commit('increment') } } })
store.dispatch('increment')
vuexでコンポーネント間のデータやり取り
コンポーネントからstoreにデータを格納する肝は、 actionsを呼び出すこと。 だからstore/index.jsでactionsを定めること、stateで定めること、mutationsを定めることが必要になる。 actionsのプロパティを呼び出すにはstore.dispatch("actionsプロパティ")を実行する。 これはイベントが起きたときにv-onのmethodsの中身のロジックにstore.dispatch("actionsプロパティ")を実行すれば良いと思われる。
Vue3について
createApp関数はVue3から使えるものだと認識した。
じゃあcreateApp関数を探そうとVue3を探したが見つからない。最終的にはvue-nextというリポジトリがVue3であることがようやく分かった。ここまですごい時間かかった。
node.jsのインストール方法(mac)
参考資料
Node.jsをmacOSへインストールする方法 | プログラミング入門ナビ
MacにNode/npmをインストールする手順 2019年1月更新 - suzu6
nodejs,npmインストールしてみた感想
macでnpmを使うには、まずnodejsが必要になる。これはnodejsにnpmが含まれているから。このnodejsをどうやってインストールするかだけれども、brew経由でnodebrewをインストールする。nodebrewは使った感じどのバージョンのnodeを使うかを指定するものの感じがする。
nodejsに関しては指定しただけでは使うことができずpathを通すことが必要になる。だからnpmのbinを探し当てて、それを~/.bash_profileに登録し、変更を反映する手続きを取る。
具体的な手順
brew install nodebrew
これでリポジトリを追加できたのでその中から使いたいversionを確認し使う。 使いたいバージョンの指定は
#node.jsをバージョンを指定してインストール nodebrew install-binary v10.16.0 #(補足:最新版を使いたい時は以下のように行う) nodebrew install-binary latest
node.jsのリストとどのバージョンを使うか定める。一言で言えばlistでnode.jsをリスト表示できる。またリストの最後に使用するnodeのバージョンが表示されている。気に入らなければuseで使いたいバージョンを定める。
$ nodebrew list v10.16.0 v14.14.0 current: v10.16.0 #現在使用する予定のバージョンはv10.16.0だと分かる
# 試しにv14.14.0に変更してみる例 $ nodebrew use v14.14.0 use v14.14.0 $ nodebrew list v10.16.0 v14.14.0 current: v14.14.0 # 変更できてる!
次にnodejsに入っているnpmのbinをbash_profileに登録することでpathを通す作業が必要になる。
npmのパスは以下になる。
$ ls ~/.nodebrew/current/bin node nodebrew npm npx # 上記のパスでnpmが存在することを確認できる!
# だからそのパスをbash_profileに登録する echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bash_profile
#変更を反映させる source ~/.bash_profile
Fragmentの画面が表示されない状況に遭遇した
ベースとなる画面にリサイクラービューを使って表示する。
そして画面遷移先で入力するためのキーボードを表示させる。その状態でベースのアクティビティに戻るとリサイクラービューを始め他のViewもろとも表示されない事態に遭遇した。いわば、レイアウトファイルそのものの存在が消え去ってしまう現象。画面遷移前にキーボードを消してからベースの画面に遷移するときちんと画面表示される。
てことでfragmentのonPause()メソッド内にキーボードを削除する関数を挿入して問題を解決した。
fun hideKeybord(fragment: Fragment){ //Fragment内でキーボード表示中の状態で元のフラグメントに戻ると、 //onResumeでレイアウトが適切に表示されない事例が発覚した。 //そのためにこの関数を作成した //キーボードの表示、非表示に関わらずこの関数は問題なく実行されることを確認している。 //ソフトキーボードを非表示 val imm : InputMethodManager = fragment.requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager imm.hideSoftInputFromWindow(fragment.view?.windowToken, 0) }
android ライフサイクルについて考え、想像するだけ
ライフサイクルはメモリ不足になるとonResumeを通ることを予期していたのにonCreateから始まることがあるようだ。
もしかするとアクティビティでフラグメントを起動して、そこから他のアクティビティに遷移する。遷移先からバックで戻ったり、アクティビティを削除すると、最初のアクティビティに戻ると思う。自分が考えていたのはアクティビティに戻ったらそのアクティビティのonResumeが呼び出されると考えていた。しかしこの考えは間違い??むしろフラグメントを起動しているアクティビティはすっ飛ばしてフラグメントのonResumeだけが呼ビダされる仕組みなのか???
Django Test retrofitが送信するデータを再現する
内容
djangoの単体テストを実装する際にAndroid端末が送信するデータ形式を再現できなければ、単体テストの効果が得られない。 したがって最初にretrofitのpostメソッドの形式を確認し、それをそれぞれどのようにdjango(python)で再現すればよいかをメモしておく。
- retrofit POSTメソッド3パターン
- djangoで再現する
1. retrofit POSTメソッド3パターン
retrofitがPOSTメソッドで送信するパターンは3種類ある。
- FORM ENCODED形式
- REQUEST BODY形式
- MULTIPART形式
//FORM ENCODED形式 @FormUrlEncoded @POST("user/edit") Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
//REQUEST BODY形式 @POST("users/new") Call<User> createUser(@Body User user);
//MULTIPART形式 @Multipart @PUT("user/photo") Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
2. djangoで再現する
前提としてretrofit POSTメソッド3パターンの例に対応する形式で記述する。
またリクエストの送信形式について調べられていないので、また分かったら理論的な側面も追記したいと思う。
FORM ENCODED形式のデータ
form形式にはinputのnameとそれに対応するvalueで送信されることから、 djangoで当該データを再現する場合にはdict形式で作成すればよい。 つまり以下を実行すれば良い。
POST_USER_URL ="/user/edit" data = {"first_name": "yasuo", "last_name": "nakanishi"} client.post(POST_USER_URL, data)
また、データとしてdict型で送信するものの、valueはjson形式で送信すると受け入れる場合がある。例えば以下のような感じ。
POST_ITEM_URL ="/hoge/hoge/" data = { "user":json.dumps({"username":"test_user"},ensure_ascii=False)} client.post(POST_ITEM_URL, data)
REQUEST BODY形式のデータを作成する
REQUEST BODY形式のデータ送信の場合は、最初にdictデータを作成する。次にそれをjson.dumps()でstr型に変換する。
またPOSTメソッド実行時にjson形式で送る旨を設定するcontent_type="application/json"を追加すれば良い。
ちなみにjson.dumpsを実行するときに、日本語が入っている等でdumpsした結果のデータが文字化けするケースに遭遇したなら、
ensure_ascii=Falseを追加しておけば文字化けは解消される。
#REQUEST BODY形式に対応したサンプル URL = "/users/new" data = {"user": {"username":"yasu", "email":"yasu@gmail.com", "gender":1 } } client = APIClient() #client.credentials(HTTP_AUTHORIZATION='Token ' + user_key) response = client.post( URL, json.dumps(data, ensure_ascii=False), content_type="application/json" )
MULTIPART形式のデータ
言語横断整理 python, kotlin, javascript
配列、リスト
オブジェクトの生成
pythonにはListがある。
foods = ["りんご", "ぶどう", "すいか", "なし"] foods = list("りんご", "ぶどう", "すいか", "なし")
kotlinにはList, Array, ArrayListがある。
var foods:List<String> = listOf("りんご", "ぶどう", "すいか", "なし") //Listは内容変更できず、要素の追加も許容しない var foods:Array<String> = arrayOf("りんご", "ぶどう", "すいか", "なし") var foods:ArrayList<String> = arrayListOf("りんご", "ぶどう", "すいか", "なし")
javascriptの場合にはArrayがある。
var foods = new Array("りんご", "ぶどう", "すいか", "なし")
リストの末尾に要素追加
#python foods.append("まんごー")
//kotlin foods.add("まんごー")
//javascript foods.push("まんごー")
条件分岐
pythonの場合にはインデントを利用した条件分岐分を書かなければならない。 またif文末にはコロンを置かなければならない。
#python if isChecked == True: return 0 elif isChecked == False: return 1
kotlinの場合にはpythonのようなelifが存在せず同じことがしたいときにはelse ifを使う。
//kotlin if (isChecked == true){ return 0 }else if (isChecked == false){ return 1}
javascriptの場合はkotlinと同じ書き方をする?
Vue.jsの最初のメモ
内容
- ドキュメント
- 基本的な使い方
- vueの内容の書き方
1.ドキュメント
2.基本的な使い方
HTMLとjavasciptのパートがあり、それを書けばvue.jsを書いたことになると現状認識している。
HTMLで書くこと
https://jsfiddle.net/5grs0976/1/
上記のコードのように、HTMLではscriptタグにVue.jsを使う旨を記述する。これはjQueryやBootstrapを使う際の記述するのと同じだから特に難しいことはない。 今回は以下のものを記述する。これはvue.jsの公式サイトに書いてあるのでそれを拾ってくると良い。
https://jp.vuejs.org/v2/guide/
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js></script>
そして反映したい内容を記述する。
https://jp.vuejs.org/v2/guide/
<p id="vm"> {{ message }} </p>
反映したい内容は上記のように{{ }}を通して表示する。この方式はdjangoのテンプレートシステムに似ている。{{}} を使う際には条件があり、テキストコンテンツに限定されるらしい。
JavaScript
vueの内容を書く。
3.vueの内容の書き方
インスタンスの生成
javascriptのフレームワークであるvueのインスタンスの生成は以下のように行う。インスタンスの引数として連想配列を渡すことになる。 今回は空の連想配列を引数としているが、キーとしてel, dataなどたくさんありキーがvueの動作を決定している。
var vm = new Vue({}) #ちなみにjavascriptArrayインスタンスの作成方法は以下の通り。 var lst = new Array("電気代","水道代","wifi料金");
Dockerについてメモ
よく使うコマンド
docker-composeコマンドを使ってサービス立ち上げ
docker-compose -f docker-compose.yml up -d --build
サービスを終了する
docker-compose -f docker-compose.yml down -v
立ち上げたサービスを使ってテストを実行する(django)
docker exec <service_name> python manage.py test
dockerのインストール
linuxの環境とwindows,macosではインストール方法が違うと分かっている。それはdockerの仕様でそうなっているようだ。以下はcentos(linux)環境でインストールする方法である。
sudo yum install docker
dockerの起動
sudo systemctl start docker sudo systemctl enable docker
dockerのイメージ取得
*例えばcentos7 sudo docker pull centos:7
以下でも実行可能
docker image pull NAME:TAG
dockerに含まれるimageの確認
以下のコマンドを実行するとdockerに含まれるイメージを表示する事ができる。 この表示にはIMAGE IDが含まれる。このIDはイメージの削除の際に必要である。
sudo docker images
docker image ls #これでも一覧する事ができる。
イメージとコンテナの関係はクラスとオブジェクトの関係と同じ。実行環境を定義したもの。 イメージはソフトウェアのテンプレートを指し、コンテナはイメージを実体化したものである。 コンテナはDockerイメージを実行して実際に作成された環境。
起動中のコンテナを一覧表示する
コンテナの一覧を以下のコマンドで表示することができる。以下のコマンドを実行すると各コンテナのIDも表示される。 このコンテナIDはコンテナを起動する際に利用するので、コンテナを一覧表示する以下のコマンドは重要である。
sudo docker ps
過去に起動したのも含めたコンテナの一覧表示は-aオプションを使う。
sudo docker ps -a
以下の方法でも同じように実行できる。
docker container ls docker container ls -a
コンテナの生成
sudo docker run -it -name dockerName centos:7 /bin/bash # 使い方: docker run [オプション] イメージ [コマンド] [引数...]
run — Docker-docs-ja 19.03 ドキュメント
コンテナの起動
sudo docker start 35634736 * sudo docker start (containerID)
以下の方法でも実行できる。
docker container run IMAGE:TAG
コンテナの停止
sudo docker stop 35634736 * sudo docker stop (containerID)
docker container stop (containerID) #これでも実行できる
イメージの作成
sudo docker commit (container ID) イメージ名:タグ
Dockerfileを元にイメージを作成する場合は以下のコマンド
docker build (Dickerfileディレクトリ)
イメージ、コンテナの削除
dockerからimageを削除する場合にはrmiコマンドを使う。コンテナを削除する場合には、rmコマンドを使う。ただし、コンテナを消す前にイメージを削除するとエラーが生じる。かならずコンテナを消してからイメージを削除する。
sudo docker rm 31435454 *sudo docker rm (containerID) sudo docker rmi 2e39r908r04 *sudo docker rmi (IMAGE ID)
イメージの削除として以下もある。
docker image rm (IMAGEID)
docker image prune #これは使われていないイメージを削除するコマンド
コンテナの削除として以下もある。
docker container rm (containerID)
Dockerfile
コンテナに直接接続してimageを更新すると、どうimageが加工されたか把握できない。これを把握するにはどう加工したかを記録に残せば良い。Dockfileには命令を記述してどうコンテナを加工したのかを可視化する。
コンテナと仮想マシンの違い
カーネルを共有しているかどうか。
疑問
Dockerイメージは軽量な方が良いとされているが、これはなぜなのか? 自分が考えるにimageがない場合はimageをダウンロードしなければならない。軽量な方がダウンロードが早くすみ開発しやすくなる??
doker-compose -コンテナの起動
docker-compose up -d --build
Imageを作成しコンテナを起動するコマンド。docker-compose.ymlからimageをダウンロードまたは作成してそれを元にコンテナを起動している。
docker-copose.yml内にbuildがあるけど、 ここにDockerfileが存在するディレクトリを書くらしい。そうするとDockerfileを読み込んでimageを作成するようだ。 docker-compose コマンドまとめ - Qiita
doker-compose -コンテナ起動の結果確認
docker-cpmpose up —build -dコマンドの結果、つまり"コンテナが起動されたか"を確認するためにdocker psコマンドを使っても確認することができない。
docker-compose ps
上記のコマンドでコンテナの起動状況を確認する事ができる。表示のうちstateを見ると確認できる。
Name Command State Ports -------------------------------------------------------------------- mydockertest_db_1 docker-entrypoint.sh postgres Exit 1 mydockertest_web_1 python manage.py runserver ... Exit 1
stateがUpであればコンテナが起動している。
stateがExit 数字の場合はエラーが発生して起動していない状態を表す。
エラー内容を確認するのは docker-compose logs {Name} 以下のコマンドで確認する事ができる。
#全部のコンテナのエラーを確認したい時 docker-compose logs #指定したコンテナのエラーを確認したい時 docker-compose logs {Name}
Dockerfileの使い方
Dockerfileを作成したらこのファイルに基づいてImageをビルドすることは分かった。dockerfileは今の所2種類の方法でimageをビルドする方法がわかった。 一つはdockerのコマンドからdockerfileを使ってビルドする方法。もう一つはdocker-compose.yml内にdockerfileを読み込む命令を記述してimageをビルドする方法である。
dockerコマンドで実行する方法は以下のようにする。
#docker build (dockerfileが存在するディレクトリ) docker build ./
docker-compose.ymlで書く方法はBuild命令を記述する。
Dockerfileの使い方-COPY
COPY命令(instruction)はホストのリソースをコンテナにコピーする役割をもつ。
#COPY ホストのコピーしたいリソース コンテナのコピー先 COPY . usr/src/app
ンテナ側であるコピー先のパスは相対パスでもいいし、絶対パスでも良いようだ。相対パスの場合WORKDIRからの相対パスとなる。
Dockerfile リファレンス — Docker-docs-ja 19.03 ドキュメント
ちなみにホスト側のカレントディレクトリはdocker-compose.ymlで読み込まれてdockerfileがビルドされる状況下でもdockerfileが存在するディレクトリがカレントディレクトリとなる。要するにいかなる場合でもDockerfileのディレクトリ。
エラー1
Docker-compose upを実行して以下のエラーが出る
ERROR: In file './docker-compose.yml', service must be a mapping, not a NoneType.
インデントがおかしい場合に表示されたのでインデントをチェックする。
エラー2
Docker-compose upを実行して以下のエラーが出る
ERROR: yaml.scanner.ScannerError: while scanning for the next token found character '\t' that cannot start any token
'\t'はタブを示しており、ymlではタブの記述は禁止されていることからdocker-compose.ymlでエラーが生じる。
インデントを使い階層構造を表現する。ただし、インデントにはタブが使えずスペースのみが使える。スペース2個単位でインデントすることが多い。
エラー3
docker-compose up コマンドを実行後、コンテナの状態を確認したところコンテナが起動していなかった。そこでdocker-compose logsを実行すると以下のエラーコードが表示された。
Error: Database is uninitialized and superuser password is not specified. db_1 | You must specify POSTGRES_PASSWORD to a non-empty value for the db_1 | superuser. For example, "-e POSTGRES_PASSWORD=password" on "docker run".
自分はpostgresをイメージに使っており、docker-compose.ymlで
db: image: postgres volumes: - postgres_data:/var/lib/postgresql/data environment: - DATABASE_DB=docker_test_db - DATABASE_USER=docker_test_user - DATABASE_PASSWORD=docker_pass - DATABASE=postgres
と表記していた。これらが原因だ。postgresは事前に用意した環境変数を使ってもらいたい意図があるようだ。
db: image: postgres volumes: - postgres_data:/var/lib/postgresql/data environment: - POSTGRES_DB=docker_test_db - POSTGRES_USER=docker_test_user - POSTGRES_PASSWORD=docker_pass - DATABASE=postgres
これで再度コンテナの起動を試みたところ無事コンテナを起動する事ができた。
エラー4
docker-compose up --build後にpython manage.py migrateを行っているのにテーブルが生成されない事例が発生。ただしデータベースはできている。。。
django.db.utils.OperationalError: could not translate host name "postgres" to address: Name does not resolve #さらには psycopg2.OperationalError: could not translate host name "postgres" to address: Name does not resolve
を確認した。これはdocker-compose.ymlの環境変数"DATABASE_HOST"の属性値が不適切であったことから生じたようだ。
services: web: build: ./web command: python manage.py runserver 0.0.0.0:8000 ports: - 8000:8000 #volumes: # - ./web/:/usr/src/app/ environment: - SECRET_KEY=bev$oyboo9ei%oewns3_6k0v-2qoq)(-5!85z2ir15p6vio - DEBUG=1 - DATABASE_ENGINE=django.db.backends.postgresql - DATABASE_DB=docker_test_db - DATABASE_USER=docker_test_user - DATABASE_PASSWORD=docker_pass - DATABASE_HOST=localhost #ココが原因 - DATABASE_PORT=5432 depends_on: - db db: image: postgres volumes: - postgres_data:/var/lib/postgresql/data environment: - POSTGRES_DB=docker_test_db - POSTGRES_USER=docker_test_user - POSTGRES_PASSWORD=docker_pass - DATABASE=postgres
以下の記事によるとDATABASE_HOSTはサービス名を値としなければならないようだ。だからこの場合はdbが正しい。
- DATABASE_PASSWORD=docker_pass - DATABASE_HOST=db #ココが原因 - DATABASE_PORT=5432
参考; Dockerで入れたPostgreSQLへのPDO接続でエラーが出て悩んだ。 - Qiita
ドッカーのドキュメントでもデータベースを司るサービス名をdjangoのsettings.pyのHOSTの値としていることが確認できる。 Redirecting…
android facebookシェアのメモ
前提
intentやShareCompatを使ったシェア方法を諦め、facebook SDKを使ってシェアを行う。
メモ
とりあえず使うにはコーディングの他に準備がある。
まずFacebookに開発者の登録が必要
facebookにアプリの登録が必要 -> appのidがandroidのマニフェストで記述する必要が出てくるから。
facebookのアプリの登録ページにはwebアプリの他にandroidアプリを作成する欄をボタンで設けることができる。
ここでキーハッシュなるものを登録する必要がある。 キーハッシュは2種類登録する。一つは開発者のキーハッシュ。これはアンドロイドスタジオ環境にはユニバーサルな値があるらしくそれを取得する。
またアンドロイドをリリースした際にはリリースしたキーも登録する。
この他にFacebook Activityを追加して、それをAndroidManifest.xmlに含めることもおこなう。
Android - Facebookログイン - ドキュメンテーション - Facebook for Developers
コーディング
facebookのシェアには種類がある。当初シェアしたい画像とともにリンクをシェアしたいと思っていたが、ルールが有るようだ。
- リンクのシェア
- 画像のシェア
- 動画のシェア
- 画像、動画が混在するマルチメディアのシェア
これらのどれに該当するかでコードが変わってくる?変わってくる.
リンクシェア ShareLinkContent content = new ShareLinkContent.Builder() .setContentUrl(Uri.parse("https://developers.facebook.com")) .build(); 写真 Bitmap image = ... SharePhoto photo = new SharePhoto.Builder() .setBitmap(image) .build(); SharePhotoContent content = new SharePhotoContent.Builder() .addPhoto(photo) .build(); 動画 Uri videoFileUri = ... ShareVideo = new ShareVideo.Builder() .setLocalUrl(videoUrl) .build(); ShareVideoContent content = new ShareVideoContent.Builder() .setVideo(video) .build(); マルチメディア SharePhoto sharePhoto1 = new SharePhoto.Builder() .setBitmap(...) .build(); SharePhoto sharePhoto2 = new SharePhoto.Builder() .setBitmap(...) .build(); ShareVideo shareVideo1 = new ShareVideo.Builder() .setLocalUrl(...) .build(); ShareVideo shareVideo2 = new ShareVideo.Builder() .setLocalUrl(...) .build(); ShareContent shareContent = new ShareMediaContent.Builder() .addMedium(sharePhoto1) .addMedium(sharePhoto2) .addMedium(shareVideo1) .addMedium(shareVideo2) .build(); ShareDialog shareDialog = new ShareDialog(...); shareDialog.show(shareContent, Mode.AUTOMATIC);
リンクのシェアはちゃんとurlの他に画像も表示される仕組みのようだからリンクシェアで良いと思われる。
とりあえずShareLinkContentに、シェアしたいリンクをsetContentUrlメソッドを実行して格納したオブジェクトを生成する。 これはandroidのクライアント側でpostを実行し、レスポンスとしてurlを返せばこのオブジェクトは使える。retrofitのonResponseメソッド内に挿入すればよいだろう。
ShareLinkContent content = new ShareLinkContent.Builder() .setContentUrl(Uri.parse("https://developers.facebook.com")) .build();
このオブジェクトをシェアするにはシェアインターフェースの実装が必要になるそうだ。 このインターフェースには種類があり、ボタンとシェアダイアログ、メッセージダイアログが存在する。
現在のsdkはシェアダイアログを開く際にユーザー端末のfacebookアプリが存在するか確認する必要がなくなったそうだ。 昔はシェアする必要があった。
この他にシェアリンクをクリックしたらアプリが自動起動する仕組みも実装することができるようだ。app linkという機能のようだ。
シェアボタンはボタンを押すとシェアダイアログを起動する機能のボタンである。
Seleniumを使ったテストのメモ
実装の際に困ったこと
django.test.LiveServerTestCaseを使う環境を把握できていなかった。
ヘッドレスモードを使う場合にはオプションに--window-sizeをつけなければならないこと。
前提
ChromeDriverを使ってseleniumを実行する
準備
seleniumをインストールする。
オプションでwebdrivermanagerをインストールしても良い。
pip install selenium
webdrivermanagerをインストールしても良い。これはseleniumが扱うChromeDriverのバージョンが異なるとエラーが出る?ようで、webdrivermanagerを使うと必要な適切なDriverをその場でインストールしてseleniumを実行するもの。
pip install webdrivermanager
LiveServerTestCaseのメモ
LiveServerTestCaseは通常のテストと同じようにassertを使ってテストする。またテストの始め方も
python manage.py test
#または
python manage.py test app.tests
で実行する。しかしながら前提としてアプリケーションサーバーを事前に起動しておく必要がある。これを行っていないとエラーが発生してしまう。
またアプリケーションサーバーのuriも同一のところにしないと当然ながらエラーが出てしまう。
アンドロイドを実機で開発しているとipを使ってrunserverするので、不一致が生じてしまうので注意すること。
seleniumを使ったテストを実行する際の注意点の資料
python - django selenium fails to load localhost - Stack Overflow
ヘッドレスモードでセレニウムを使う
def setUp(self): chrome_options = webdriver.ChromeOptions() chrome_options.add_argument('--headless') chrome_options.add_argument('--window-size=1920,1080') self.driver = webdriver.Chrome(ChromeDriverManager().install(), chrome_options=chrome_options)
ヘッドレスでテストを行うと画面上にブラウザが表示されないのがメリット。 ヘッドレスで起動するにはオプションを追加すれば使える。ChromeOptions()インスタンスを生成し、インスタンスにadd_argument('--headless')メソッドと引数を与えてからwebdriver.Chromeインスタンスを生成すれば良い。
別のオプションとして'--window-size=1920,1080'を追加している。これはオプションを使わずに.click()メソッドを使ってもクリックできない場合があって、それに対応するためのもの。