drf_writable_nestedを試してみた
Django Restframeworkを使ってAPIを書くとコードの記述量が少なくて良いのですが、ネストしたオブジェクトの更新が煩雑になる点がちょっと不満です。ネストしたオブジェクトの更新をしようとすると途端に記述量が増えます。
実際、公式ドキュメントを見ると、
def create(self, validated_data): tracks_data = validated_data.pop('tracks') album = Album.objects.create(**validated_data) for track_data in tracks_data: Track.objects.create(album=album, **track_data) return album
とあります。ForeignKeyフィールドであるtracksをpopしてからcreateする必要があります。updateも同様。これはイマイチ。。。
と思っていた所以下のパッケージがあったので使ってみました。 github.com
確認コードはこちら。 簡単に動かしてみた限りでは便利そうです。
今回のコードはこちらに置いてあります。 https://github.com/koty/drf_writable_nested_sample
時間をみつけて、いろんなパターンを試してみたいと思います。
vue.jsを始めてみた
最近社内で突如としてSPA熱が高まっていて、勉強がてら作っている。
vue-cliでboilerplate的なものはできるので、そこからちょびちょびと機能追加していった。行の選択に応じて下部の詳細部分が書き換わる。reactiveで良い感じ。
Reactに取り組んでいる人がいて様子を見るにかなり苦戦している。慣れれば、あるいは大規模なシステムだと、Reactの方が効率が良いのかもしれない。だけど最初の入りやすさから自分はvueを選んだ。ちょっとかじっただけでもここまでできるのだからvueは最初のハードルは低いんじゃないだろうか。
この調子で、家業の伝票印刷システムのweb版を作りたい。どれくらいかかるか分からないけど。webpackの使い方とか全然分からないまま作っているけどとにかく動くものを作ることを優先する方が性に合う。
Django Background Tasksでお手軽バックグラウンド処理
バックグラウンドで動くバッチ処理を作りたい時にスケジューラを使うと思います。Pythonで代表的なタスクスケジューラはCeleryですかね。 でも、単に、長めの処理をキューイングしてシリアライザブルに実行していきたいといった簡単な要件だとちょっと大げさ過ぎるように感じ、他の仕掛けを探した所 Django Background Tasks というパッケージがあったの今回使ってみました。
基本的には、ドキュメントに書いてある通りですが。。
まずインストール。利用した時点でのバージョンは 1.1.0rc2
でした。django-background-task
(単数形)というパッケージも存在するのでご注意。今回紹介する複数形のは単数形のをforkしている模様です。
pip install django-background-tasks
settingsに設定を追記します。
INSTALLED_APPS = [
・・・
'background_task',
・・・
キューを保持するためのテーブルを作るので、migrateします。migrationファイルが含まれていないので、makemigrationsから。migrateすると、background_task
およびbackground_task_completedtask
というテーブルができます。
./manage.py makemigrations background_task ./manage.py migrate
タスクの定義。これだと、queue_name1というキューにキューイングし、5秒後に実行する、という設定です。
from background_task import background @background(queue='queue_name1', schedule=5) def some_long_duration_process(some_param1, some_param2): # 何か長い処理
タスクを呼び出す方の書き方です。普通にメソッドを呼んでいるように見えますが、実際にはキューイングされるだけでメソッドは呼び出されません。 @background
デコレータの内部でメソッド呼び出しが横取りされ、キューイングが行われます。background_taskテーブルを見ると分かるように引数はJSONにシリアライズされるので、確認はしていませんがJSONにシリアライズできる必要があると思われます。
# 登録側 some_long_duration_process('a', 'b')
説明の順番が若干前後しますが、予め以下のコマンドでバックグラウンドタスクを処理するプロセスを起動しておきます。
./manage.py process_tasks
サーバー構築時には、supervisordの下で動くようにしておきます。
[program:process_tasks] command=/.../bin/python ./manage.py process_tasks --settings=my_proj.settings.prod directory=/... user=centos autostart=true autorestart=true stdout_logfile=/.../...log ; 標準出力ログ stdout_logfile_maxbytes=1MB stdout_logfile_backups=5 stdout_capture_maxbytes=1MB redirect_stderr=true
そこそこ細かい設定もできるようですし、Celeryは大げさだなという場面では有効に使えると思いました。
SPAのOpen Graph Protocol 対応について。さらにCloudFrontを経由した場合についてのつらい話。
もう半年以上前になってしまうけど、この話題。
サーバーサイドレンダリング不要論 - Qiitab.hatena.ne.jpogp出すためにUAを見てアプリケーションサーバーに投げたりしてるけどcloudfrontでは既定でUAが書き換えられちゃうのでキャッシュヒット率落ちるのを覚悟の上でUAを通すという辛い状況。
2016/12/24 17:32
client → cloudfront → ELB → EC2(nginx → gunicorn )
という構成。
- nginxのリバースプロキシにて
/api
はgunicornにルーティング - それ以外は try_filesで /index.html を返すという設定
基本的にはこれで動く。しかしOGPが問題。この作りだとOGPの生成にはJavaScriptが動く必要があるが、twittterやFBのクローラーはJavaScriptを解釈しない。なので、nginxでUser-Agentを見てSNSのクローラーだった場合はgunicornに処理を委譲しOGPのみを描画したドキュメントを返すようにした。
if ($http_user_agent ~ "facebookexternalhit") { ・・・ proxy_pass http://127.0.0.1:8000; ・・・
ところが、User-AgentはCloudFrontの既定の設定だと"Amazon CloudFront"に書き換えられてしまい、上記の判定ができない。仕方ないので、以下のようにCloudFrontでUser-Agentヘッダを通すよう設定した。*1 これで判定は通るようになる。しかしUser-Agentを通したことでキャッシュヒット率は落ちる。うむー。SNSのクローラーがJavaScriptを動かすようになるか、CloudFrontが CloudFront-Is-Crawler-Viewer といったヘッダを用意してくれるとありがたいんだけど。
*1:ちなみに画像にあるようにCloudFront-Is-*ヘッダも使ってみたのだけど、今回の要件には使えなかった
let's encryptで証明書を取得する際はIP制限を外しておく必要がある
メモ書き。
EC2(Amazon Linux)でlet’s encryptからSSL証明書を取得した。基本的には以下の記事の通りにやればOK。 tkuchiki.hatenablog.com
certbot-auto を実行する際、最初セキュリティグループでhttpをアクセス制限していたのでスクリプトが失敗していたが、外したら成功した。 apacheのログには以下のようなものが記録されていた。
66.133.109.36 - - [08/Jun/2017:00:52:18 +0000] "GET /.well-known/acme-challenge/ランダム文字列 HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
考えてみれば当たり前なんだろうけど。。ググると、アクセス元の66.133.109.36
は固定されたIPのようなので、次回からはこのIP指定でアクセス制限しても良いかもしれない。
pypiデビューした
Pythonistaなら誰もがあこがれる(よね?)、pypiパッケージへのデプロイをビクビクしつつやってみた。
諸事情でStackPathのAPIを叩きたかったのだけどPythonのAPIがなかったのでやってみた。実際にはStackPathの前身であるMaxCDNのAPIをForkするだけだったので胸を張ってパッケージオーナーとは言いづらい。。。お手軽さとしてはpypiデプロイ初体験として最適だったと思う。
ところでStackPathはフリープランが無くて試用期間が2週間しかないので、それ以降は自腹を切らんとメンテできない。どうしようかな。
実際のpypiへのデプロイ手順はこちらのとおりなので特に書くことはございません。。。(ぉぃ qiita.com
世界でいちばん簡単な Pythonプログラミングのe本[最新版] Pythonアプリ作りの考え方が身に付く
- 作者: 金城俊哉
- 出版社/メーカー: 秀和システム
- 発売日: 2017/03/21
- メディア: 単行本
- この商品を含むブログを見る