Raspberry Pi 2 Model B + docker-compose上に、Django + PostgreSQLなアプリをデプロイしてみた

Raspberry Pi 2 Model Bを使ってDjangoアプリを作ろうかなと思いました。

環境構築をどうするかと考えたところ、RaspbianでDockerを動かせると知りました。
Docker comes to Raspberry Pi - Raspberry Pi

Dockerが動くならdocker-composeもいけるのではと思い、調べてみたところ動かしている方々がいました。

そこで、Raspberry Pi 2 Model B + docker-compose上に、Django + PostgreSQLなアプリをデプロイしてみました。

 
目次

 

環境

 
なお、DjangoアプリやDockerまわりの設定は、公式チュートリアルを改変したものです。
Quickstart: Compose and Django | Docker Documentation

 

Raspbian 2018-04-18のセットアップ

以前の記事を参考にセットアップしました。
Python2 + Scapyで、Raspberry Pi 2 Model B をブリッジにできるか試してみた #router_jisaku - メモ的な思考的な

内容としては、

です。

 

デプロイするものを作成

以下の

  • Djangoアプリ
  • Dockerfile
  • docker-compose.yml

GitHubにpushしておきます。

 

Djangoアプリ

今回作成するDjangoアプリは

  • localhost:8000/myapp/<pk> にアクセスするとTemplateViewを返す
  • Django adminを利用可能
  • MacではSQLite、Raspbian上ではPostgreSQLを使用
  • makemigrationsも実施済
  • 環境変数により、DBバックエンドをSQLitePostgreSQLのどちらかを利用する

という簡単なものです。

リポジトリにpushしてあるので、今回は省略します。
https://github.com/thinkAmi-sandbox/rpi_docker_django_postgres-sample

 
なお、requirements.txtも用意しましたが、PostgreSQL用のライブラリとして psycopg2-binary を指定しました。

リリースノートによると、2.7.4からパッケージが分かれ、 psycopg2-binary を使うように書かれているためです。
http://initd.org/psycopg/articles/2018/02/08/psycopg-274-released/

そのため、psycopg2を指定するとワーニングが出たため、 psycopg2-binary を指定しています。

 

Dockerfile

Docker公式チュートリアルのものです。

FROM python:3
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt
ADD . /code/

 

docker-compose.ymlの作成

こちらは、公式チュートリアルのものを一部修正しています。

  • 外部からPostgreSQLに接続できるよう、dbにポートを追加
  • Docker上かどうかを判断するため、 IS_DOCKER という環境変数を設定
    • 良い方法でないかもしれませんが、今回はお手軽に...
version: '3'

services:
  db:
    image: postgres
  web:
    build: .
    command: python3 manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    depends_on:
      - db

 

RaspbianにDockerまわりをインストール

  • Docker
  • docker-compose

をインストールします。

 

Docker

公式ブログの通り、Dockerをインストールします。

pi@raspberrypi:~ $ curl -sSL https://get.docker.com | sh

# Executing docker install script, commit: 36b78b2
+ sudo -E sh -c apt-get update -qq >/dev/null
+ sudo -E sh -c apt-get install -y -qq apt-transport-https ca-certificates curl >/dev/null
+ sudo -E sh -c curl -fsSL "https://download.docker.com/linux/raspbian/gpg" | apt-key add -qq - >/dev/null
Warning: apt-key output should not be parsed (stdout is not a terminal)
+ sudo -E sh -c echo "deb [arch=armhf] https://download.docker.com/linux/raspbian stretch edge" > /etc/apt/sources.list.d/docker.list
+ [ raspbian = debian ]
+ sudo -E sh -c apt-get update -qq >/dev/null
+ sudo -E sh -c apt-get install -y -qq --no-install-recommends docker-ce >/dev/null
+ sudo -E sh -c docker version
Client:
 Version:      18.05.0-ce
 API version:  1.37
 Go version:   go1.9.5
 Git commit:   f150324
 Built:        Wed May  9 22:24:36 2018
 OS/Arch:      linux/arm
 Experimental: false
 Orchestrator: swarm

Server:
 Engine:
  Version:      18.05.0-ce
  API version:  1.37 (minimum version 1.12)
  Go version:   go1.9.5
  Git commit:   f150324
  Built:        Wed May  9 22:20:37 2018
  OS/Arch:      linux/arm
  Experimental: false
If you would like to use Docker as a non-root user, you should now consider
adding your user to the "docker" group with something like:

  sudo usermod -aG docker pi

Remember that you will have to log out and back in for this to take effect!

WARNING: Adding a user to the "docker" group will grant the ability to run
         containers which can be used to obtain root privileges on the
         docker host.
         Refer to https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface
         for more information.

 
インストール時のログに従い、 docker グループに pi ユーザを追加します。

pi@raspberrypi:~ $ sudo usermod -aG docker pi

 
念のため、再起動しておきます。

pi@raspberrypi:~ $ sudo shutdown -r now 

 

docker-compose

docker-composeはpipでインストールします。

なお、 sudo 忘れると docker-compose コマンドが使えなかったので、忘れずにつけておきます。

pi@raspberrypi:~ $ sudo pip install docker-compose
...
Successfully installed PyYAML-3.12 backports.ssl-match-hostname-3.5.0.1 cached-property-1.4.2 docker-3.3.0 docker-compose-1.21.2 docker-pycreds-0.2.3 dockerpty-0.4.1 docopt-0.6.2 functools32-3.2.3.post2 jsonschema-2.6.0 texttable-0.9.1 websocket-client-0.47.0

 

ソースコードをclone

Raspbian上の適当なディレクトリに、GitHubリポジトリをcloneしておきます。

pi@raspberrypi $ git clone https://github.com/thinkAmi-sandbox/rpi_docker_django_postgres-sample.git .

 

manage.pyの実行

1回限りの作業

  • migrate
  • loaddata
  • createsuperuser

docker-compose run で実行していきます。

 

migrate

初めて docker-compose コマンドを使ったため、migrate前に色々な設定が走ります *1

pi@raspberrypi $ docker-compose run web python manage.py migrate

Creating network "docker_django_default" with the default driver
Creating docker_django_db_1 ... done
Building web
Step 1/8 : FROM python:3
 ---> 98281429ea18
Step 2/8 : ENV PYTHONUNBUFFERED 1
 ---> Running in 913b4e88ef19
Removing intermediate container 913b4e88ef19
---> 52f2af605dd4
Step 3/8 : RUN mkdir /code
---> Running in 272a8670ae9e
Removing intermediate container 272a8670ae9e
---> ab158a0f4822
Step 4/8 : WORKDIR /code
Removing intermediate container d991836249af
---> 35eec4df510b
Step 5/8 : ADD requirements.txt /code/
---> 0f31d94edaf2
Step 6/8 : RUN pip install -r requirements.txt
---> Running in ecf1decd7b32
Collecting django (from -r requirements.txt (line 1))
 Downloading https://files.pythonhosted.org/packages/23/91/2245462e57798e9251de87c88b2b8f996d10ddcb68206a8a020561ef7bd3/Django-2.0.5-py3-none-any.whl (7.1MB)
Collecting psycopg2-binary (from -r requirements.txt (line 2))
 Downloading https://files.pythonhosted.org/packages/77/09/4991fcd9a8f4bea1ee3948e1729fa17c184d25bd10809bacc143626361b9/psycopg2-binary-2.7.4.tar.gz (426kB)
Collecting pytz (from django->-r requirements.txt (line 1))
 Downloading https://files.pythonhosted.org/packages/dc/83/15f7833b70d3e067ca91467ca245bae0f6fe56ddc7451aa0dc5606b120f2/pytz-2018.4-py2.py3-none-any.whl (510kB)
Building wheels for collected packages: psycopg2-binary
 Running setup.py bdist_wheel for psycopg2-binary: started
 Running setup.py bdist_wheel for psycopg2-binary: still running...
 Running setup.py bdist_wheel for psycopg2-binary: still running...
 Running setup.py bdist_wheel for psycopg2-binary: finished with status 'done'
 Stored in directory: /root/.cache/pip/wheels/60/a9/b1/390d13a4c6ae769c74c56efdd25573d76b9fba441430189658
Successfully built psycopg2-binary
Installing collected packages: pytz, django, psycopg2-binary
Successfully installed django-2.0.5 psycopg2-binary-2.7.4 pytz-2018.4
Removing intermediate container ecf1decd7b32
---> 4cb1031555c5
Step 7/8 : ADD . /code/
 ---> cfa31851aba0
Step 8/8 : ENV IS_DOCKER true
 ---> Running in 9d76ae22228f
Removing intermediate container 9d76ae22228f
 ---> dd8368ef0606
Successfully built dd8368ef0606
Successfully tagged docker_django_web:latest
WARNING: Image for service web was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, myapp, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying myapp.0001_initial... OK
  Applying sessions.0001_initial... OK

 

fixture
pi@raspberrypi $ docker-compose run web python manage.py loaddata initial_data

Starting docker_django_db_1 ... done
Installed 1 object(s) from 1 fixture(s)

 

createsuperuser
pi@raspberrypi $ docker-compose run web python manage.py createsuperuser

Starting rpi_docker_django_postgres_sample_db_1 ... done
Username (leave blank to use 'root'): admin
Email address: admin@example.com
Password: 
Password (again): 
Superuser created successfully.

 

docker-composeによる起動

docker-compose up で起動します。

pi@raspberrypi $ docker-compose up

docker_django_db_1 is up-to-date
Creating docker_django_web_1 ... done
Attaching to docker_django_db_1, docker_django_web_1
db_1   | The files belonging to this database system will be owned by user "postgres".
db_1   | This user must also own the server process.
...
db_1   | 2018-05-24 12:39:39.750 UTC [1] LOG:  database system is ready to accept connections
web_1  | Performing system checks...
web_1  | 
web_1  | System check identified no issues (0 silenced).
web_1  | May 24, 2018 - 12:42:26
web_1  | Django version 2.0.5, using settings 'myproject.settings'
web_1  | Starting development server at http://0.0.0.0:8000/
web_1  | Quit the server with CONTROL-C.

 

接続確認

curl

問題なく動作していました。

$ curl http://192.168.10.201:8000/myapp/1/

<div class="container">
    ふー
</div>

 

Django admin

Django adminのログイン〜データ作成まで問題なくできました。

f:id:thinkAmi:20180524215923p:plain:w300

 
追加したデータへのcurlも成功しました。

$ curl http://192.168.10.201:8000/myapp/2/
<div class="container">
    ばー
</div>

 

PostgreSQL

psql を使って、登録したデータを確認します。

 

接続

まず、Raspbian上で docker-compose psPostgreSQLのポートがRaspbianに転送されているかを確認します。

# docker-compose.ymlファイルが存在するディレクトリにいることを確認
pi@raspberrypi $ ls -al
...
-rw-r--r-- 1 pi pi  282 May 26 12:30 docker-compose.yml

# PostgreSQLの5432ポートが、Raspbianの9876ポートに転送されていることを確認
pi@raspberrypi $ docker-compose ps
       Name                      Command               State           Ports         
-------------------------------------------------------------------------------------
docker_django_db_1    docker-entrypoint.sh postgres    Up      0.0.0.0:9876->5432/tcp
docker_django_web_1   python3 manage.py runserve ...   Up      0.0.0.0:8000->8000/tcp

 
次に、RaspbianもしくはMac上で psql を使って接続します。

# Macの場合
$ psql -h 192.168.10.201 -U postgres -p 9876
psql (10.3, server 10.4 (Debian 10.4-1.pgdg90+1))
Type "help" for help.

postgres=# 

 

テーブル一覧とデータの確認

\dt で、テーブルの一覧を確認します。Djangoのテーブルがあるようです。

postgres=# \dt
                   List of relations
 Schema |            Name            | Type  |  Owner   
--------+----------------------------+-------+----------
 public | auth_group                 | table | postgres
 public | auth_group_permissions     | table | postgres
 public | auth_permission            | table | postgres
 public | auth_user                  | table | postgres
 public | auth_user_groups           | table | postgres
 public | auth_user_user_permissions | table | postgres
 public | django_admin_log           | table | postgres
 public | django_content_type        | table | postgres
 public | django_migrations          | table | postgres
 public | django_session             | table | postgres
 public | myapp_foo                  | table | postgres
(11 rows)

 
続いて、データを確認します。

postgres=# select * from myapp_foo;
 id | name 
----+------
  1 | ふー
  2 | ばー
(2 rows)

 

psqlの終了

データが確認できたので、 \qpsqlを終了します。

postgres=# \q

 

停止

Ctrl + C にて停止します。

^CGracefully stopping... (press Ctrl+C again to force)
Stopping docker_django_web_1 ... done
Stopping docker_django_db_1  ... done

 

いらないものを削除

docker-compose down にて削除します。

# 現在の環境を確認
pi@raspberrypi $ docker-compose ps

       Name                      Command                State     Ports
-----------------------------------------------------------------------
docker_django_db_1    docker-entrypoint.sh postgres    Exit 0          
docker_django_web_1   python3 manage.py runserve ...   Exit 137        
pi@raspberrypi:~/work/docker_django $ docker-compose images
     Container           Repository        Tag       Image Id      Size 
------------------------------------------------------------------------
docker_django_db_1    postgres            latest   af4e361a5ae8   218 MB
docker_django_web_1   docker_django_web   latest   d0958cc8b3f7   619 MB

# いらないものを削除
pi@raspberrypi $ docker-compose down
Removing docker_django_web_1     ... done
Removing docker_django_web_run_4 ... done
Removing docker_django_web_run_3 ... done
Removing docker_django_web_run_2 ... done
Removing docker_django_web_run_1 ... done
Removing docker_django_db_1      ... done
Removing network docker_django_default


# 削除されていることを確認
pi@raspberrypi $ docker-compose ps

Name   Command   State   Ports
------------------------------

pi@raspberrypi $ docker-compose images
Container   Repository   Tag   Image Id   Size
----------------------------------------------

## Dockerイメージは残っていることに注意
pi@raspberrypi $ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
docker_django_web   latest              d0958cc8b3f7        About an hour ago   649MB
postgres            latest              af4e361a5ae8        9 days ago          228MB
python              3                   98281429ea18        2 weeks ago         608MB

 

Raspbianシャットダウン

すべて終わったので、Raspbianをシャットダウンしておきます。

pi@raspberrypi $ sudo shutdown -h now 
Connection to 192.168.10.201 closed by remote host.
Connection to 192.168.10.201 closed.

 

ソースコード

GitHubに上げてあります。
https://github.com/thinkAmi-sandbox/rpi_docker_django_postgres-sample

 

参考

*1:時々、 「django.db.utils.OperationalError: could not connect to server: Connection refused」が発生します。ただ、再度実行すると成功します。タイミングなのでしょうか...

Python 3 エンジニア認定基礎試験に合格しました

5/18にPython 3 エンジニア認定基礎試験を受けてきました。
基礎試験 | 一般社団法人Pythonエンジニア育成推進協会

無事に合格したため、メモを残します。

 

受験した経緯

社内Slackにて試験話が盛り上がっていました。

自分もビッグウェーブに乗ろうとPython 3 エンジニア認定基礎試験の受験要項を調べたところ、当日申込でも午後に受験できると知りました。東京すごい。
対象試験(コン検、Rails、ビジネス統計、リユース検定、Python)申込みから受験までの流れ|オデッセイ テスティング センター

 

試験まで

毎日Pythonにふれているとはいえノー勉強ではマズイだろうと思い、先に合格している同僚の受験記を参考に、何をすれば良いか確認しました。
Python 3 エンジニア認定基礎試験に合格しました - プログレッシブ・プロレタリアート

模試があるとのことだったので、DjangoCongress JP参加のために上京する車中にて

をしました。

模試は試験の形式が分かったので、目を通しておいて良かったです。

また、Pythonチュートリアル本には、知らなかった内容も書かれていたため、参考になりました。

 

結果

無事に終わって良かったです。

DjangoCongress JP 2018で発表するまでの準備を振り返ってみた #djangocongress

前回書いた通り、DjangoCongress JP 2018にて発表しました。
DjangoCongress JP 2018

ただ、カンファレンスでの発表は未経験だったので、ゼロから準備をしました。

今書かないと忘れてしまいそうなので、発表するまでの準備を振り返ってみます。

 
なお、CfPを出した時点の、自分のスペックは以下の通りです。

  • Blog書いているので、文章を書くのは苦にならない
  • 話すのは苦手
  • 勉強会でのLTは経験あるが、毎回やっても緊張が解けない
  • 45分のトークは未経験

 
目次

 

長いのでまとめ

  • CfP・スライド・動画が公開されているPyCon JPの情報はありがたい
    • 2012年〜2017年まである
  • 発表資料作成は、Marpさまさま

 

CfP出すまで

社内のCfPネタ出しにて、sin_tanaka からMiddlewareネタでいけると言われました。

(ヾノ・∀・`)

と思ったのですが、ネタをもらったのに何もしないのは良くないと考え、CfPを提出することにしました。

 
とはいえ、CfPを書いたことがないのでフォーマットを探しました。

PyCon JPのサイトを見ると、プロポーザルリストがありました。
https://pycon.jp/2017/ja/proposals/vote_list/

 
そこで、PyCon JPのプロポーザルに従って、以下のプロポーザルを3/5に出しました。締切直前...

対象レベル:
初級


説明:
Djangoでアプリケーションを作る際、全部のリクエスト/レスポンスをフックし、何か処理を行いたいことがあります。

例えば、全画面でログイン必須にするとします。この場合、全部のViewに対してデコレータ・Mixinを追加しても良さそうです。

しかし、その場合、同じような処理を複数箇所に書くことになります。その結果、新規作成やメンテナンス時の作業漏れにより、不具合が発生する可能性があります。

そうならないための仕組みとして、DjangoにはDjangoミドルウェアという仕組みがあります。これを使うことで、リクエスト/レスポンスをフックして、自分の処理を追加できます。

また、DjangoはWSGIに沿ったフレームワークのため、WSGIミドルウェアを使用してもリクエスト/レスポンスをフックできます。

そこでこのセッションではDjangoにDjango/WSGIミドルウェアを組込む例を示しながら

・なぜDjango/WSGIミドルウェアを使うのか
・Djangoミドルウェアとは
・WSGIミドルウェアとは
・WSGIとは
・ミドルウェアを複数組み込んだ時の動作順
・ミドルウェアでの例外ハンドリング
・Djangoミドルウェア/WSGIミドルウェアの実例

などをご紹介します。


話せないこと:
・凄いDjango/WSGIミドルウェアを作って公開した経験や話


備考:
以前ブログに書いた内容を元に、最近のDjangoに追随した内容を予定しています。
http://thinkami.hatenablog.com/entry/2016/12/13/061856

 
その4日後、

thinkAmi さんの「Django/WSGIミドルウェアについて」は選考の結果、採用となりました。

の連絡をいただきました。驚きました。

 

タスク洗い出しとスケジュール化

ボーっと過ごしているとあっという間に本番を迎えそうだったため、タスクの洗い出しとスケジュール化を行いました。

弊社内のGitLabにリポジトリを作り、Boardを使ってタスク化しました。

今振り返ると、スケジュールを破ったものが多いですが、タスクの洗い出しができていたため、そこまで焦ることはありませんでした。

 

発表方法の調査

カンファレンスでの発表方法について、そもそもよく分かっていないことに気づきました。

そこで、PyCon JPのサイトを見たところ、過去の動画が公開されていました。
https://pycon.jp/2017/ja/schedule/

そのため、それらの動画を視聴し、流れや雰囲気などを確認しました。

 
また、合わせて近隣の図書館に出かけ、タイトルに プレゼン発表 と名前が付いている書籍を読みました。

乱読するうちに、発表は

  • TEDっぽいの
  • 企業間のコンペっぽいの
  • 学会発表っぽいの

の3種類に分かれそうだと気づきました。

今回のDjangoCongress JPネタの場合、学会発表が一番近いだろうと感じました。

そのため、学会発表 と書かれているものについても読むことにし、最終的には20冊くらいになりました。

 
複数の書籍を読んだことで、どの書籍でも言われていることを中心すればハズレがなさそうとの実感を得ました。

当日も、「理系のための口頭発表術」をお守り代わりに持っていきました。

理系のための口頭発表術―聴衆を魅了する20の原則 (ブルーバックス)

理系のための口頭発表術―聴衆を魅了する20の原則 (ブルーバックス)

 

プレゼン小道具の検討

動画や書籍を見たり、軽くプレゼンの素振りをするうちに、プレゼン小道具がいるかもしれないと思い、検討してみました。

 

プレゼンター

動画を見るとプレゼンターを使っている方がいたため、どんな機能が必要か考えてみました。

 

スライド切替

スライド切替なしでもいけそうでした。

ただ、当日の緊張を考えると、スライドの進むボタンを押せばいいだけになるスライド切替器が欲しくなりました。

 

レーザーポインタ

スライドで説明している部分を指すのがあると良いかなと思いました。

ただ、当日の緊張を考えると、ポインタ位置がブレブレになり見づらくなるだろうと考えました。

そのため、今回レーザーポインタはやめておきました。

 

最終的に用意したもの

ロジクールR400t です。

ロジクール ワイヤレス プレゼンター R400t

ロジクール ワイヤレス プレゼンター R400t

大きめで握りやすいのと、スライドを進めるボタンが押しやすそうということで選びました。

サポートOSにはMacの文字はありませんでしたが、ドライバをインストールしなくてもそのまま使えました。

 
R400tにはレーザーポインタ機能がありますが、前述の通りレーザーポインタは使いません。

そこで、指し棒を使えば、スライドで説明している部分を指せると思いました。

ただ、片方の手にハンドマイク、もう片方にR400tを持つと、手が足りません。

都度持ち替えすることも考えましたが、当日の緊張を考えると、持ち替える時にそれらを落とす可能性が高そうでした。

 
仕方ないので、指し棒は使わず、

  • 位置を示す必要がないくらいまで、スライド中の情報量を減らす
  • 減った情報量は、スライドの枚数を増やすことで、全体の情報量は変更しない

とスライド構成でカバーすることにしました。

 

時間配分表

時間厳守するために、何らかの方法が必要でした。

そんな中、以下の記事を目にしました。
岡山で「ITエンジニアの生存戦略」について話してきました #oso2018 - give IT a try

この中の「60分ちょうどで発表を終わらせるコツ」にて、時間配分表について書かれていました。

まさにこれだと感じ、自分も用意しました。

 
とはいえ、前日のホテルで気づいたので、ホテルのWindowsとプリンターを借りて出力しました。

そのWindowsにはOffice系のソフトが無かったため、ワードパットを使ってフォントサイズを調整しつつ、何とか出力しました。

 
なお、失敗したのは、時間配分表の書き方でした。

時間が増える形式で書いたものの、会場のプレゼンタイマーは時間が減っていく形式でした。

そのため、発表しつつ残り時間を計算するハメになりました。

 

一般的なスライド量の把握

45分の場合、どれだけ枚数を用意すれば良いのか分かりませんでした。

そこで、PyCon JPのトーク時間とスライド量を調べてみました。

その結果、自分の説明能力であれば80枚前後を用意すれば何とかなるという目安が得られました。

 
とはいえ、実際に書いてみたところ、最終的には105枚になってしまいましたが...

 

スライドの作成

PowerPointのようなプレゼンソフトにいきなり書いていく場合、全体像が見えなくて苦しむだろうと考えました。

そのため、Blogを書くような感じで

  • 目次を作成
  • 目次に従い、Markdownで内容を追加

という順で作業を行いました。

 
また、スライドの形式で見れば気づくことも多そうと考え、Markdownをスライド化できるMarpを使いました。
Marp - Markdown Presentation Writer

元データがMarkdownだったので、資料のページを入れ替えるなども楽でした。

なお、スライドを書いている時点では、Marpを使った発表は考えていませんでした。現時点(v0.0.12)では、プレゼンテーションモードが搭載されていないためです(pdf書き出しは可能)。

 

発表の素振り

1週間くらい前に、ひと通りのスライドができあがったため、発表の素振りを始めました。

スマホの音声レコーダーを使いながら、スライドを読み上げました。

その際、詰まったところや説明しづらいと気づいたら、随時、音声レコーダーを一時停止しつつスライドの修正を行いました。

最初の頃、読み上げとスライドの修正を別の時間でやろうとしたら、スライドの修正箇所を忘れてしまったこともあり、これはやってみないと分からないと感じました。

 
とはいえ、最初は読み上げるのが手間であり、積極的にやろうという気にはなりませんでした。

ただ、素振りを繰り返していくうちに、話しやすいスライドに修正されていくことに気づき、これは良いとの実感を得ました。

そのため、時間をみて素振り & 資料修正するようになりました。

 
10回を超えた頃からだいたい内容が頭に入り、長さがバラバラだった発表時間も安定するようになりました。

素振りの回数は発表の得手不得手により変わってくるかと思いますが、自分はこれくらいやらないとダメでした。

 

あきらめた発表スタイル

素振りを繰り返すと、自分にできることとできないことが大体わかってきました。

あきらめたスタイルは次のようなものです。

 

スライドの量を減らして、口頭説明多くする

元々アドリブが弱いため、口頭説明を臨機応変にやると失敗すると感じました。

そのため、スライドに内容をある程度書いて、あとは読み上げていくスタイルにしました。

とはいえ、素振りして何となく覚えてしまったものは、スライドから削除していきました。

 

落ち着いた語り口

緊張すると早口になるため、落ち着いた語り口にしようと考えていました。

しかし、どうやっても緊張がとれません。

そのため、時間配分表を見て、あまりに早い場合には軌道修正しようと考えました。

 

ウケを狙う

日頃できないものは無理なので、あきらめました。

 

Marpについて

今回はMarpで書き出したpdfを使いました。その経緯や対応は以下です。

 

プレゼンツールの選択(Marp & pdf)

だいたいの内容が固まった3日前くらいに、PowerPointなどのプレゼンツールに移植しようと考えました。Marpにプレゼンテーションモードが無かったというのもあります。

ただ、何も設定していないPowerPointだったので、フォントの用意やマスタースライドの調整など、移植するまでに時間がかかりそうでした。

そのため、Marpでスライドをpdf化し、Adobe Readerのフルスクリーン表示で発表することにしました。

 

Marpのテーマ変更

MarpのGaiaテーマを使うことで、パッと見、いい感じのスライドになりました。

ただ、MarpのGaiaテーマで気になったのは、ソースコードの背景が黒だったことです。

黒背景はターミナルっぽくて良いのですが、過去の知見より、会場の光量によってはスライドが見づらくなると感じました。

そのため、以下の内容でテーマを変更しました。

  • 黒背景から、白背景へ
  • バックのグラデーションをとりやめ
  • 色数を減らすため、シンタックスハイライトを sunburst から github

 
なお、Marpでのスタイル変更は、以下の記事が参考になりました。ありがとうございました。

 
また、変更したテーマは、Marpをforkして、ブランチ theme/thinkami の中に入れてあります。
https://github.com/thinkAmi/marp

 

前日

書籍「理系のための口頭発表術」に、「発表練習は前日夜にはやらない」と書かれていたため、前日朝を最後に練習はやめました。

社内Slackが資格試験で盛り上がっていたので自分も参加してみたり、フラフラ散歩していました。

 

当日

当日は、緊張のために食欲もそんなにわかないだろうと思い、ベーグルとゼリー飲料を持ち込みました。

その時間になると、案の定、緊張してました。そのため、食欲がありませんでしたが、飲み込みやすいものだったためお腹にものを入れることができ、空腹を避けられました。

 
また、時間配分表のおかげで、前半遅れたのを把握できたので、後半調整できました。そのおかげで、1分くらい残して発表を終えました。ただ、質疑応答の時間が取れずに申し訳なかったです。

発表の結果については、前回の記事にも書きましたが、好意的な意見が多くてホッとしました。

 

まとめ

再掲となりますが。

  • CfP・スライド・動画が公開されているPyCon JPの情報はありがたい
    • 2012年〜2017年まである
  • 発表資料作成は、Marpさまさま

 
めったにない経験ができて、とても楽しかったです。ありがとうございました。

DjangoCongress JP 2018 に参加 & 発表しました #djangocongress

5/19に開催された、DjangoCongress JP 2018に参加 & 発表しました。
DjangoCongress JP 2018

場所は、サイボウズ株式会社の東京オフィスでした。
東京オフィス アクセスマップ | サイボウズ株式会社

 
会場の内装が凝っていたり、バーっぽいところがあったり、スカイツリーが見えたりと、素敵な会場でした。

 
自分の発表、および全体を通してのメモを残します。誤りがありましたらご指摘ください。

 
目次

自分の発表「Django/WSGIミドルウェア入門」

スライドです。

また、発表で使用したソースコードは、以下のリポジトリに公開してあります。
https://github.com/thinkAmi/DjangoCongress_JP_2018_talk

なお、プレゼンの対応バージョンは

です。

 
プレゼン資料は

を元に構成しました。

 
その結果、主な内容は

となりました。

 
なお、公式ドキュメントに記載が無いがプレゼン資料に記載したものは

  • process_view() の戻り値が render() メソッドを持つ場合は、 process_template_response() フックも動作する

の箇所です。

ソースコードを見ると

となっており、また動作も確認していますので、問題ないかと思います。

 
発表自体は緊張のあまり早口 & カミカミでしたが、聴いてくださっていた方々のツイートを見ると好意的なコメントをいただけていたようです。ありがたいばかりです。

 
また、発表直後に運営者の方々から

  • 初めてなのに発表が上手だった (@hirokikyさん)
  • スライドがシンプルにまとまっていてよかった (スタッフの方 *1 )

という旨のフィードバックをいただきました。最低限の仕事は果たせたのかなと感じるとともに、発表に不慣れな自分には今後の励みや指針となりました。ありがとうございました。

また、即座のフィードバックを通じて、DjangoCongressをより良いものにしようというスタッフ間での意識の浸透を感じました。

心残りは、発表終了直後も余裕がなかったせいもあり、@hirokikyさんに「DjangoCongress JPを開催してくださってありがとうございます」と直接お伝えできなかったことです。かわりにこの場にて感謝申し上げます。

 
ところで、Djangoと自分について振り返ってみると、自分がDjangoを本格的に始めたのは2015年8月くらいだったようです。
Python + Django + Highcharts + Herokuで食べたリンゴの割合をグラフ化してみた - メモ的な思考的な

当時は今よりもさらに日本語の情報が少なく、公式チュートリアルやQiitaのDjango入門、「Two Scoops of Django」本での独学でした。

それから時は流れ、Python + Djangoメインの会社に転職し、仕事で本格的にPythonDjangoができるようになり、Django入門の著者と一緒に働いています。そして、今回のDjangoCongress JP 2018で発表と、Djangoでの縁がいろいろとつながっています。

そのDjangoのカンファレンスにて、Djangoコミュニティに少しでも何かを返すことができたのであれば何よりです。

 
というところで、以降は当日のメモです。

 

オープニング

Chairpersonの@hirokikyさん

資料:DjangoCongress 2018 Opening - Google スライド

PyCon JP 2017の

Why don’t you make a Conference for Django?

からすべてが始まったんだなと感じさせてくれる良いオープニングでした。

また、Code of Conductにもふれられており、とても大切にしているということが伝わってきました。

 

できる!Djangoでテスト!

tell-kさん

資料:できる!Djangoでテスト!

自分のDjangoのテストの書き方で本当にいいのか分からなくて参加しました。

テスト全般〜Djangoのテストまで、いろいろとまとまっていて参考になりました。

特に、

が自分にとっての新しい発見でした。

また、モックのパッチでのハマるポイントについては、過去の自分に教えてあげたい感じでした。

 

GeoDjangoではじめる地理空間情報

小俣 博司さん

資料:GeoDjangoではじめる地理空間情報 // Speaker Deck

元々地図に興味があったのと、以前Open Street Mapの勉強会に参加したことがあり、Djangoと地図ってどういう関係なんだろうと思い、参加しました。
第38回 #NSEG OpenStreepMapマッピングパーティ in 小諸 に参加してきました - メモ的な思考的な

プレゼンは、地理空間情報に関する細かな内容でした。いろいろな用語が散りばめられ、入門する時のよい資料となりそうでした。

あとは印象に残ったところを自分のTweetから転記しておきます。

  • ORMで空間演算
    • 空間演算関数をSQLに組み込んでいる
  • DjangoとOpen Street Mapを結び付けられる
  • WebGISが流行ってきている
  • 測地系と座標系
  • 座標の表現方法は何種類もある
  • Google Mapはメルカトル図法
    • 南極と北極を表現せず、割り切っている
  • 地図情報、ファイルにもいろいろと種類がある(ベクトルとラスタ等)
  • シェープファイルGIS業界のデファクトスタンダード
    • 日本語の文字情報はShift_JISが比較的多い
  • GeoJSON、RFC化されてる。RFC7946
  • PostGISの情報が多い。慣れなうちはこれを使うと良い
  • 最初にためしてみるなら、Leaflet.jsがおすすめ。ただし、Google Mapに感しては、いろいろ複雑
  • 古い地図は、地理院地図が良い
    • 大正時代など、昔のデータも揃ってる
  • Djangoに統合されているため、コンソールにモデルの形式が定義されて表示される
    • modelを作るのが楽で良さそう
  • GeoJSONSerializerなんてのもある
  • デモについて
    • リアルタイムで風の流れが見える
    • つぶやきの場所が見える
  • 地図データ、よく知らないだけでいろいろなものが公開されてる

 

Building your MVP with Django: Lessons Learned Building and Launching a SaaS

James Van Dyneさん

資料:Building your MVP with Django: Lessons Learned Building and Launching a SaaS // Speaker Deck

MVP(Minimum Viable Product)な書き方が気になったので参加しました。

  • ManyToManyFieldを、throughを使うようにする
  • クラスベースビューを避ける
  • テンプレートでは、(余計な)include()ではなくインラインにする

あたりが印象に残りました。

今まで何でもクラスベースビューにしていましたが、必要に応じて関数ベースビューも、と考える良いきっかけとなりました。

 

Djangoにおける認証処理実装パターン

Masashi Shibataさん

資料:Django における認証処理実装パターン - c-bata web

認証処理のカスタマイズに興味があったため、参加しました。

発表の詳細は上記ブログに掲載されているため、ここではその中でも印象に残ったものを記載します。

  • Djangoの認証機能が表にまとまっていた
  • 他の人のライブコーディングを見ると、いつもどんな風に操作しているのか参考になる
    • こんなこともできるなど
  • カスタムユーザモデルは、プロジェクトの開始直後くらいでやっておくとマイグレーションで苦しまない
  • Userモデルのusername、Python3だとunicodeを受け入れてしまう
    • ASCIIUsernameValidator を使うと良い
  • unicodedata.normalize() で、表現を正規化できる

 

Django REST framework 実践入門

Masataka Araiさん

資料:Django REST framework 実践入門 - slideship.com

最近Django REST frameworkにさわっていたのですが、まだ雰囲気でしか使っていないので参加しました。

  • まずはSerializerをおさえる
  • Command-Query分離の原則
    • 入力用と出力用のSerializerを分ける
  • サードパーティライブラリの紹介が、入門者にとっての道案内になっていて助かった
    • drf-writable-nested
    • djangorestframework-camel-case
    • drf-nested-routers
    • django-silk
    • django-js-reverse
  • 質疑応答の方々がみんな使っているばかりで、どんな点に悩むのかが分かった

 

LT

全部で5つのLTがありました。どれも楽しめました。

Python Web History

aodagさん

PythonのWebフレームワークの歴史に関するLTでした。

歴史的経緯などが分かりやすくまとまっていました。Werkzeug(2007)のあとにFlask(2010)が登場したというのが収穫でした。

 

Python out LOUD podcast

ケビンさん

Pythonpodcastに関するLTでした。

いろいろなpodcastがあり、英語を学ばないとなーと改めて感じました。

 

Djangoの同人誌を書いた話

akiyokoさん

資料:Django の同人誌書いた話

 / Kiso Django at techbookfes4 // Speaker Deck

技術書典4で頒布されたDjangoの同人誌についてのLTでした。

同人誌執筆の裏側が見えました。あと、LT資料の中に自分のTweetが引用されていて嬉しくも恥ずかしい気持ちになりました。

また、LT後に執筆してくださったことへの感謝を直接お伝えできて良かったです。

 

Django Girlsとゆかいな仲間たち

Django Girlsの紹介でした。
Django Girls - start your journey with programming

Django Girlsチュートリアルは良いという認識でいましたが、2018年の開催も全国へと展開していて、いろいろと輪が広がっていくのすごいと感じました。

 

サイボウズ株式会社のコネクト支部より

会場を提供してくださったコネクト支部の紹介と、勉強会会場情報のLTでした。

今回のような素晴らしい会場を無償提供してくださっているとのことでした。

東京会場は会議室っぽくなくて、リラックスした雰囲気で参加できたのでとても良かったです。

 

謝辞

最後に謝辞です。

まずは日本システム技研(JSL)の方々、プレゼンの素振りをはじめ、いろいろとご協力いただきありがとうございました。

特に、このネタならCfP行けると言ってくれた sin_tanaka、当初の資料が入門用なのに分かりづらいと気づかせてくれた pro_proletariat、 想定問答や題材をもらった moonwalkerpoday にはとても感謝しています。

なお、プレゼン資料や発表で分かりにくいところ・誤りがあれば、それは全部自分の責任です。

 
また、会場の提供をしてくださったサイボウズ株式会社さま、素敵な場所をありがとうございました。Room2のバーっぽい雰囲気は、登壇初経験のプレッシャーをやわらげてくれ、とてもやりやすくなりました。

 
最後になりましたが、DjangoCongress JP 2018のスタッフ、発表者、参加者のみなさま、ありがとうございました。楽しい時間を過ごせました!

*1:お名前を聞きそびれ、申し訳ないです...

「現場で使える 基礎Django」を読みました #技術書典

最近Djangoを使う人も増えてきているようで、自分がさわり始めた頃に比べれば、分からないことことでも探せば出てくるようになりました。

とはいえ、Djangoの全体像をさらっとながめられるようなものがあまりなく、自分のDjango自体の理解が正しいのか悩んでいます。そのため、Djangoの公式ドキュメントとは異なった視点のものがほしいなと思っていました。

 
そんな中、先日の技術書典4にて「現場で使える 基礎Django」が頒布されると聞いたため、入手して読んでみました*1

Django自体の解説書がほしかった自分にとっては、本書はニーズに合った本であり、とても満足できました。

以下、簡単に感想やメモを残しておきます。

 
ちなみに、今はBoothでも販売されているようです。
現場で使える 基礎 Django【紙の本】※部数限定 - あきよこブログ(akiyoko - BOOTH(同人誌通販・ダウンロード)

 

本の対象読者と自分

本書のp7を引用すると、対象読者は

  • Pythonの文法はある程度分かるけどDjangoは初めてという初心者の方
  • Djangoを始めてみたけれど今いちコツが掴めないという初級者の方
  • Djangoのベストプラクティスを学びたいと考えている中級者の方

とのことです。

ちなみに、自分の経験は

です。

 

感想

本書では、Djangoの基礎的なところからちょっと深いところまで、アプリを作る上で必要そうな範囲がまとめられていました。

書籍全体を通して図を使って解説されていました。特に、

をはじめとした、「Django公式ドキュメントには書いてあるけれど、図がほとんどないのでイメージがわかない」ものに対して処理フローが書かれていました。

そのため、あまり気にせず使っていたり、処理フローがぼんやりしている分野について、理解を深められました。

 
例えば、昔、バリデーションの処理フローを調べたことがありました。
Djangoで、CreateViewでPOST後に動作する、ModelFormやModelのバリデーションを試した - メモ的な思考的な

Blogではフローを図に書き起こしていなかったため、あとから読み返すと理解しづらいなと感じていました。

そんな中、本書にバリデーションフローの図が掲載されていたため、「ほしかったのはこれだ」となりました。

 
また、自分の理解が浅かった

  • モデルマネージャーとその役割
  • INSTALL_APPSの書き方
  • ロギングの設定

なども学べて良かったです。

 
その他、良いと感じたところは、

  • 理由とともにベストプラクティスが掲載されており、他の人の考え方を学べたこと
  • 本に従ったサンプル実装が著者のGitHubで公開されていたため、実際のアプリではどんな感じで実装しているか見られたこと
  • 全体を通して、クラスベースビューを使っていたこと *3

です。

 
執筆後記にも書かれている通り、本書に掲載されていないことはまだまだあります。ただ、検索するためのキーワードは本文中に散りばめられているため、あとから調べる時に役に立ちそうです。

 
一方、注意すべきことは、この本はチュートリアルではないということです。

そのため、自分のように「まずは何か書いてみて概要をつかみ、後で公式ドキュメントを読んで理解する」タイプの人は、本書を読む前に、Djangoの公式チュートリアルDjango入門を行っておくと、理解が深まるのかなと感じました。

 
これからもDjangoをさわる機会はあるかと思います*4。ただ、日々Djangoにさわっていないと忘れてしまう内容もあるため、Djangoアプリを作るときには手元に置いて参考にしたいと思います。

id:akiyoko さん、良い本をありがとうございました。

*1:技術書典4自体の参加記録:http://thinkami.hatenablog.com/entry/2018/04/24/224740

*2:Django入門の著者である同僚も、この本を購入していました

*3:自分は関数ベースビューがよく分からないので...

*4:仕事で使えると最高ですね!

技術書典4に行ってきました #技術書典

4/22に秋葉原UDX アキバ・スクエアで開かれた、技術書典4に行ってきました。

techbookfest.org

 
イベント自体は知っていたのでいつかは行きたいなーと思っていました。そんな中、日本語で書かれたDjango本「現場で使える基礎Django」が頒布されると聞いたので、行くことにしました。

 
ただ、このようなイベントには初参加であり、勝手がよく分かりませんでした。そのため、事前に公式ブログや参加のチュートリアル的なブログを読んでおきました。

 
当日は現地でkobayutaponさんと合流し、会場入りしました。

整理券が配布されると聞いていたので、早めに行ったところまだ配布されていませんでした。そのため、ヨドバシカメラでうろうろしていたら、整理券が配布されました。

会場に向かうとすでに多数の人が並んでいて、整理券をもらうのにもしばらく待ちました。自分たちは500番台でした。

 
開始まで時間があったため、またヨドバシカメラでうろうろしていました。しばらくすると入場開始のお知らせがあり、会場へ向かいました。整理券を受け取ったときよりも待機列が伸びていたので驚きました。

 
整列して入場し、まずは「現場で使える基礎Django」を購入しました。

人が多くて会話できませんでしたが、Djangoの本を執筆してくださってありがとうございますという気持ちでした。

 
その後は同僚に頼まれた本を購入したり、気になる本を探して会場をうろうろしていました。入り口でトートバックをもらったため、人が多い中でも本の持ち運びがしやすく助かりました。

当日の戦利品はこちらです。

 
また、ポスターもいただきました。今はギークラボ長野に貼ってあります。

 
お昼前に会場を後にして、技書話人伝へ行きました。
技書話人伝

こちらはゆったりと本を見れました。技術書同人誌展示コーナーも楽しめました。

その後、お昼ごはんを食べたり、低レイヤーのお店めぐりをしました。低レイヤーはあまり詳しくないので、kobayutaponさんの解説はありがたかったです。

 
最終的には2万歩くらい歩いて身体に疲労感がありましたが、熱量あふれる技術書を見るのは楽しく、良い一日でした。また、技術書を書くのも面白そうだなーと感じました。

運営者・サークルのみなさま、ありがとうございました。

「OSSライセンス」勉強会に参加しました #nseg #glnagano

4/21に、ギークラボ長野にて開催された「OSSライセンス」勉強会に参加しました。
「OSSライセンス」勉強会 - connpass

 
テクニカルライター/ITライターの可知豊さんの講演の他、フリーテーマのLTがありました。

昔、ライセンスまわりを調べていた時、可知さんの書籍に出会って非常に助かったため、当日を楽しみにしていました。

ライセンスまわりは何となく理解していましたが、OSS著作権の関係をすっかり忘れていたため、色々と学べて良かったです。

 
以下簡単なメモです。誤っていたらご指摘ください。

 
目次

 

オープンソースライセンスの基礎と実務(ダイジェスト版)

スライド:オープンソースライセンスの基礎と実務

スライドのダイジェスト版の講演でした。重要と思われるところを中心に話していただいて、理解しておいたほうが良いポイントが分かりました。

印象に残ったところは以下です。Tweetできなかったところは他の方のTweetを引用します。

 
また、最近、趣味で機械学習のモデルを作っていたため*1、作ったモデルのライセンスに関する質問をしてみました。

という回答をいただけました。

 
他に、可知さんにサインをいただきました。ありがとうございました。

 
なお、書籍の最新版は電子書籍にて提供・販売されています。内容も適宜更新されるそうなので、こちらをどうぞ*2
知る、読む、使う! オープンソースライセンス - 達人出版会

 

LT

フリーテーマでしたが、いずれも(資格試験含む)ライセンスまわりのLTでした。

 

AWS認定ソリューションアーキテクトアソシエイト取得への道 (katekichiさん)

LTを聞いて、地道に勉強するしかないと感じました。

業務で学んだことが出題され、資格勉強で得た知識を業務にいかせているとのことでした。

 

MySQLのライセンス (とみたさん)

スライド:MySQLのライセンス

MySQLのライセンスまわりについてのLTでした。

  • MySQL本体のライセンス(GPLと商用)
  • クライアントライブラリのライセンス(GPL)
  • ライセンスの関係上、MariaDBの機能をMySQLの商用には取り込めない

が印象に残りました。

 

とある実例

とある実例のお話でした。

「やってしまったのは仕方ない、正直に対応する」というのが印象に残りました。大事。

 

農業AIアイデアソンに参加してきた (kotyさん)

スライド:農業AIアイディアソンに参加してきた // Speaker Deck

当初の予定とは変更し、農業AIアイデアソンに関するLTでした。

いつもリンゴは食べる側でしかなく、栽培については書籍でちらっと知った程度なので、現場のお話がちらっと聞けて良かったです。

また、農業における暗黙知形式知にするのは、大変だけど重要そうだと感じました。

 

その他

受付係をしました。出席率100%でありがたいことです。

お菓子係も行いました。当日暑かった & 前回担当より参加者多かったため、飲料とお菓子を1セットずつ増やしました。

ただ、ちょっと量が多かったかもしれませんので、ここらへんはまた担当する時に考えたいと思います。

 
最後になりましたが、可知さんをはじめとする関係者のみなさま、ありがとうございました。

*1:http://thinkami.hatenablog.com/entry/2018/04/16/080742

*2:Amazonを見たらプレミアムがついていて驚きました...