diadia

興味があることをやってみる。自分のメモを残しておきます。

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を使いたい。。。
色んな方法で実現できると分かった。

  • cdnを使う方法
  • vue cliを使う方法
  • vue cliを使わないで行う方法

最終的には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.js

環境構築方法をメモしておく。

前提: - 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ここにアクセスして以下が表示されればココまではおっけい。 f:id:torajirousan:20200703094305p:plain

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

下のように表示されればおっけい f:id:torajirousan:20200703110443p:plain

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

html - Exception Value: string indices must be integers : Render bundle error vue + django - Stack Overflow

render_bundle failing with TypeError: string indices must be integers · Issue #227 · owais/django-webpack-loader · GitHub

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つの処理を一つにまとめているだけである。その処理は、

  • データバインディングで、タグのvalue属性(値)を更新する
  • イベントハンドリング(イベントが発生したときに呼び出される処理)で、受け取った値をデータに代入

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と呼ばれ、centosyumに相当するものである。

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であることがようやく分かった。ここまですごい時間かかった。

GitHub - vuejs/vue-next at v3.0.0

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リポジトリを追加する。

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)で再現すればよいかをメモしておく。

  1. retrofit POSTメソッド3パターン
  2. 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);

retrofit公式サイトより

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型で送信するものの、valuejson形式で送信すると受け入れる場合がある。例えば以下のような感じ。

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の最初のメモ

内容

  1. ドキュメント
  2. 基本的な使い方
  3. vueの内容の書き方

1.ドキュメント

https://jp.vuejs.org/

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のイメージ取得

Docker Hub

*例えば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個単位でインデントすることが多い。

YAML覚書 - Qiita

エラー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()メソッドを使ってもクリックできない場合があって、それに対応するためのもの。

ヘッドレスモードでクリックが反応しない場合の対処に関する資料

python - Is it possible to use `element.click()` on Selenium with Chrome even on headless mode? - Stack Overflow