@kotyのブログ

PythonとかAWSとか勉強会のこととかを、田舎者SEがつづります。記事のライセンスは"CC BY"でお願いします。

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を経由した場合についてのつらい話。

もう半年以上前になってしまうけど、この話題。

サーバーサイドレンダリング不要論 - Qiita

ogp出すためにUAを見てアプリケーションサーバーに投げたりしてるけどcloudfrontでは既定でUAが書き換えられちゃうのでキャッシュヒット率落ちるのを覚悟の上でUAを通すという辛い状況。

2016/12/24 17:32
b.hatena.ne.jp

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 f:id:kkotyy:20170801171259p:plain これで判定は通るようになる。しかしUser-Agentを通したことでキャッシュヒット率は落ちる。うむー。SNSクローラーJavaScriptを動かすようになるか、CloudFrontが CloudFront-Is-Crawler-Viewer といったヘッダを用意してくれるとありがたいんだけど。

*1:ちなみに画像にあるようにCloudFront-Is-*ヘッダも使ってみたのだけど、今回の要件には使えなかった

なつかしのtypist

中学でFM-TOWNSを使う機会があったけど、本格的にコンピュータを使うようになったのは大学のUNIX端末だった。そこで最初にtypistというコンソールアプリで練習をしてタッチタイピングができるようになっていった。今思えば驚きの地味さ加減なアプリケーションだ。

ということをふと思い出して今使うのはどうすればいいのだろうと調べたら、homebrewで入るらしい。

brew install gnu-typist

f:id:kkotyy:20170727131000p:plain

タッチタイピングできてない人はこれで練習したら良いと思う。

以上おっさんの昔話でした。(もっとまともな記事を書かないと。。。)

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パッケージへのデプロイをビクビクしつつやってみた。

pypi.python.org

諸事情でStackPathのAPIを叩きたかったのだけどPythonAPIがなかったのでやってみた。実際にはStackPathの前身であるMaxCDNのAPIをForkするだけだったので胸を張ってパッケージオーナーとは言いづらい。。。お手軽さとしてはpypiデプロイ初体験として最適だったと思う。

ところでStackPathはフリープランが無くて試用期間が2週間しかないので、それ以降は自腹を切らんとメンテできない。どうしようかな。

実際のpypiへのデプロイ手順はこちらのとおりなので特に書くことはございません。。。(ぉぃ qiita.com