読者です 読者をやめる 読者になる 読者になる

Django REST frameworkで爆速API開発 開発編 serializers その①

エンジニアの島袋です。 開発編ということで、導入編でさらっと触れたDjango REST frameworkの肝の一つであるserializersについて書いて行きたいと思います。 公式ドキュメントのここら辺を参考に書いていきます。 ちなみに爆速なのは開発スピードであって、APIのレスポンスタイムではないです。

導入編
開発編 serializers その① ← 今ココ

serializers

直列変換器(Serializers)という名前の通り、最終的にはmodelデータをJSONで出力するための機能。 表示するデータの選別や表示内容の変更に、バリデーションからのCRUD処理をこのクラスで制御(提供)することができます。

サンプル

下記コマンドで新規Appを作って試していきます。

python manage.py startapp drink

今回は一番需要が高いであろうModelSerializerで紹介していきます。

まず初めにこんなmodels.pyがあるとします。

from django.db import models

class Supplier(models.Model):
    name = models.CharField(max_length=50)
    charge = models.CharField(max_length=50)

class Drink(models.Model):
    name = models.CharField(max_length=50)
    price = models.IntegerField()
    discount = models.IntegerField()
    supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE)

対応するserializers.pyファイルを作ります。

from rest_framework import serializers
from .models import Drink, Supplier

class SupplierSerialiser(serializers.ModelSerializer):
    class Meta:
        model = Supplier

class DrinkSerializer(serializers.ModelSerializer):
    class Meta:
        model = Drink

view.pyファイルを用意したり、マイグレーションしたり、データをゴニョゴニョ用意して、http://127.0.0.1:8000/drink/を見るとこんなデータを得られます。

{
    "count": 2,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 1,
            "name": "",
            "price": 100,
            "discount": 75,
            "supplier": 1
        },
        {
            "id": 2,
            "name": "麦茶",
            "price": 110,
            "discount": 100,
            "supplier": 2
        }
    ]
}

ね。簡単でしょ?

表示フィールド

データの中でも表示させたくないものってありますよね? そんな時はこんな風に…

class DrinkSerializer(serializers.ModelSerializer):
    class Meta:
        model = Drink
        fields = ('name', 'price', 'discount')

表示したいのカラムだけを書き加えるだけで、http://127.0.0.1:8000/drink/の表示が…

{
    "name": "",
    "price": 100,
    "discount": 75
}

になるという素敵仕様。

逆に表示したくないカラムを指定したり、

class DrinkSerializer(serializers.ModelSerializer):
    class Meta:
        model = Drink
        exclude = ('supplier',)

特定のカラムを読み込み専用(更新不可)にしたり、

class DrinkSerializer(serializers.ModelSerializer):
    class Meta:
        model = Drink
        read_only_fields = ('name',)

実はurlなんて便利なものがあったり

class DrinkSerializer(serializers.ModelSerializer):
    class Meta:
        model = Drink
        fields = ('name', url)
{
    "count": 2,
    "next": null,
    "previous": null,
    "results": [
        {
            "name": "",
            "url": "http://127.0.0.1:8000/drink/1/"
        },
        {
            "name": "麦茶",
            "url": "http://127.0.0.1:8000/drink/2/"
        }
    ]
}

めちゃくちゃ便利な機能が簡単に利用できます。

外部キーによる参照

実際は上記の表示だけでも運用は可能といえば可能ですが、Drinkクラスのsupplier(仕入先)の情報も同時に欲しいですよね? そんな時はこんな感じで…

class DrinkSerializer(serializers.ModelSerializer):
    supplier = SupplierSerialiser()
    class Meta:
        model = Drink

serializersを書き換えるだけで、http://127.0.0.1:8000/drink/1/の表示が…

{
    "id": 1,
    "supplier": {
        "id": 1,
        "name": "A社",
        "charge": "田中"
    },
    "name": "",
    "price": 100,
    "discount": 75
}

素敵に早変わりします。

ちなみに、下記のようにMetaクラスに1行追加するだけでも同じような結果が得られます。

class DrinkSerializer(serializers.ModelSerializer):
    class Meta:
        model = Drink
        depth = 1

簡単すぎて、設計さえガッツリやればコピペだけでいいんじゃないか、というレベルです。

まとめ

というわけで、開発編 serializersクラスの基本的使い方①でした。 serializersは、データを実際にどう見せるかといった制御を行うレイヤーで、DBからデータを取り出し、表示用に加工してViewクラス渡すのが主な仕事に一つになってます。

次回は、開発編 serializersクラスの使い方② InsertやUpdate、バリデーションといったデータの更新周りをお届け予定。

テクノロジーサイドからみた○○ x Tech

ここの5〜6年の間 (特定の分野) x Techというワードをよく聞きます。 長年「ITの不毛の分野」と言われてた産業にテクノロジーが注入される事により、○○ x Techと称されます。 近年だと、Ad Tech、Fin Tech、Ed Tech、Fashion Tech、Food TechそしてHR Tech等があります。

ちなみには我々もHRテクノロジー大賞奨励賞というのを昨年受賞しています。

それぞれの分野でテクノロジーのトレンドとビジネスのトレンドがうまく合致するタイミングで、○○Techというワードがメディアにでてくる事になります。もしくは恣意的に業界全体が出すように仕向けます。 GoogleApple等の大手だけがこれらのメリットを享受するのではなく、それぞれの分野で新しいスタートアップが現れます。 スタートアップが新しいテクノロジーを生み出す事もあれば、大手企業が生み出したテクノロジーにスタートアップがうまくビジネスに取り入れるパターンがあります。 過去の○○Techというのを振り返ってみると、それぞれの時代でソフトウェア・ハードウェア問わずどういったテクノロジーの進化があったのでしょうか。

Ad Tech(広告 x テクノロジー)

  • 2009年頃〜
  • リアルタイムで入札できる仕組みの登場(RTB)
  • 複数のアドネットワークへの配信の登場(DSPSSP)
  • リーマンショック後、ニューヨークの金融関係者がこの業界に流れた(都市伝説?)

株式の自動取引のテクノロジーが広告の自動入札に流れてきたとか言われてましたが、RTBの登場後は広告枠を買う人と売る人の間に様々なプレイヤーが現れました。

Ed Tech(教育 x テクノロジー)

  • 2011年頃〜
  • タブレットの登場により、幼児教育にタブレットが使われる
  • 通信環境の改善によるICTを活用した遠隔授業、MOOCs
  • 学校の教職員のITリテラシー向上、ITに慣れ親しんでる年齢層が決裁者になってきている

タブレット登場後、幼児教育を中心とした知育アプリが乱立しました。また、映像配信に耐えうる通信環境とクラウドサーバーにより大学が社会人に向けた講座をオンラインで開講する等の動きが加速しました。

Fin Tech(金融 x テクノロジー)

上記は支払い関係を効率化するものがメインですが、保有資産の一元管理するツール(Money Tree, Money forward等)が多くでてきてこれも含めFinTechですね。現金をあまり使わないアメリカの方がこのあたりは盛んな感じがします。

HR Tech(人材 x テクノロジー)

では、今流行りのHR Tech流行の背景はなんなのかをテクノロジーサイドから読み解くと、実はそこまで多くでてきません。 HRと一言でいっても候補者獲得、スクリーニング、戦力化、タレントマネジメント、人事労務管理等があり、HR Techはスクリーニングとタレントマネジメントの部分で語られる事が多いです。 他の産業と同様にテクノロジーの動きをみてみると、大きなところで

等があります。

これだけ? と思うのですが、ビジネスサイドでないテクノロジーサイドにフォーカスすると案外少ないです。 機械学習の大衆化というのは、大量のデータを効率よく溜め込んでいくというのは、その辺のアプリケーションエンジニアやインフラエンジニアでも可能になりました。そして機械学習の部分もライブラリも豊富に揃っているのでデータサイエンティストだけの仕事ではなくなりました。(その先の意味ある分析から戦略立案は彼らの仕事ですね)

そして人工知能ブーム。人に代わって人工知能が採用して育成してくれるというのはまだ先の話で、あくまで人の思考をサポートする役割にとどまります。

人工知能がHRの領域で活躍するには、デジタル化されてない人の行動ログがもっと必要です。 人の活躍・気持ちの変化を察知するには、人の行動ログが大量に必要なのにも関わらず、まだデジタル化された情報だけに頼っています。 声の大きさ、歩く速度、会話の量など人の状態を把握するのに必要なデータは正規化されてないオフラインにある事が多いです。これをデジタル化するとHR Techというのはもっと加速するはずです。この辺りは人工知能の出番かもしれないですね。

最後に脱線しますが、社会保険の電子化はもっと加速してほしいです。 年末調整の用紙に自分で計算した金額書き込んで保険会社からのはがき添付して提出する文化がなくなるのはいつになるのでしょうか。

PHPプロファイラ XHProf と XHGui と Callgraph をインストール

こんにちは、エンジニアのあらきです。
最近、外はめっきり寒くなってきました。

うちのマンションは昭和生まれということで気密性が低いです。さらに窓や扉の高さが低いため、午前中でも奥まで光が入ってきません。
なので朝と夜はメチャ寒い。特に朝。
もうね、ほんと、布団が恋しい(´ー`)
身体が重くて布団から出られません(´ー`)

・・・

重いといえば!

色々と開発をしている中で、いつの間にかやたらと表示が重いページが出てきます。何秒とかかかります。メモリが256MBだとか、回線がISDNだとかではありません。

「いったいどこが重いねん(゚д゚)」

ってことで、Facebook製のPHPプロファイラ『XHProf』をローカル環境にインストールして、どのメソッドがノロマな亀になっているのかを探りました。

環境

  • PHP 5.6
  • nginx(今回はSSLページに設定)
  • MySQL

目標

XHProfで取得した情報を、XHGuiとCallgraphで確認できるようにして、ボトルネックを発見する

XHProfのインストール

まずはXHProfのインストールをしましょう。

$ pecl install channel://pecl.php.net/xhprof-0.9.4

次にphp.iniを編集してインストールしたXHProfを認識させます。

$ vim /etc/php.ini

# 最終行でいいので、以下を入力
[xhprof]
extension=xhprof.so

ウェブサーバーを再起動して、インストールの確認をします。

# nginxを再起動
$ /etc/init.d/nginx restart

# インストール確認
$ php --ri xhprof

xhprof => 0.9.2

XHGuiのインストール

続いてXHGuiのインストールです。

XHGuiのダウンロード

まずはXHGuiをダウンロードしましょう。
(今回は直接ファイルをダウンロードする形で進めていきます)
https://github.com/pierrejoye/xhprof-pr
f:id:i-plug-develop:20161101164421j:plain

ダウンロードしたzipを解凍。xhprof-prフォルダをドキュメントルートに設置します。

# xhprof-pr → xhprofにリネームしました
$ ~/public_html/xhprof

$ cd ~/public_html/xhprof

各種ファイルの編集

次に各種ファイルの編集を行っていきます。

# header.phpファイル
$ vim external/header.php
// コメントアウト
register_shutdown_function('xhprof_shutdown_function');
 ↓
// register_shutdown_function('xhprof_shutdown_function');

configファイルはサンプルからコピーを作成します

# サンプルからコピーを作成
cp xhprof_lib/config.sample.php xhprof_lib/config.php
// DBの情報を適宜設定
$_xhprof['dbtype'] = 'mysql'; // Only relevant for PDO
$_xhprof['dbuser'] = 'user';
$_xhprof['dbpass'] = 'password';
$_xhprof['dbname'] = 'xhprof';
$_xhprof['dbadapter'] = 'Pdo';
$_xhprof['url'] = 'https://xhprof.example.jp';
// $controlIPs = falseを有効に
// $controlIPs = false;
$controlIPs = array();
$controlIPs[] = "127.0.0.1";
$controlIPs[] = "::1";
 ↓
$controlIPs = false;
// $controlIPs = array();
// $controlIPs[] = "127.0.0.1";
// $controlIPs[] = "::1";`|

データベースの設定

次にデータベースの設定を行います。

-- MySQLにDB名『xhprof』を作成
mysql> CREATE DATABASE xhprof;

続いてテーブルを作成しますが、xhprof_lib/utils/Db/Pdo.phpの冒頭にCreate table文がコメントアウトで記載されているので、それをそのまま実行します。

$ vim xhprof_lib/utils/Db/Pdo.php
mysql> CREATE TABLE `details` (
         `id` char(17) NOT NULL,
         `url` varchar(255) default NULL,
         ...

nginxの設定

次にnginxの設定を行っていきましょう。 まずは、おおもとのnginx.confにconf.d以下のconfファイルを読み込む設定をします。

http {
    ...

    include /etc/nginx/conf.d/*.conf;
}

続いて、xhprof用のconfファイルを作成します。

$ vim /etc/nginx/conf.d/xhprof-ssl.conf
server {
    listen       443;
    server_name  xhprof.example.jp;

    ssl on;
    ssl_certificate /etc/nginx/ssl.hoge.crt;
    ssl_certificate_key /etc/nginx/ssl.hoge.key;

    set_real_ip_from   172.31.0.0/16;
    real_ip_header     X-Forwarded-For;

    root   /home/example/xhprof/xhprof_html/;
    index  index.html index.php;

    location = /robots.txt { access_log off; log_not_found off; }
    location = /favicon.ico { access_log off; log_not_found off; }

    location ~ \.(php|phar)$ {
        expires off;
        include /etc/nginx/fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }
}

そして、解析するサイトのconfファイルにxhprofのheader.phpとfooter.phpを読み込むように設定

$ vim /etc/nginx/conf.d/example-ssl.conf
location ~ \.(php|phar)$ {
    include /etc/nginx/fastcgi_params;

    ...

    # 以下を追加
    fastcgi_param PHP_VALUE "auto_prepend_file=/var/www/example/public/xhprof/external/header.php \n auto_append_file=/var/www/example/public/xhprof/external/footer.php";
}

ここまで設定できたらnginxとphp-fpmを再起動します。

$ /etc/init.d/nginx restart
$ /etc/init.d/php-fpm restart

設定は以上です。

XHProfでの解析のON/OFFと解析データ確認

解析

XHProfでの解析を行う場合、解析したいページURLに『_profile=1』パラメータをつけてアクセスします。
https://example.jp?_profile=1
アクセスすると、以降停止するまで自動で解析し続けます。
ページ遷移をした場合は、遷移先のページが解析されます。

解析を停止するには、URLに『_profile=0』をつけてアクセスします。
https://example.jp?_profile=0

データ確認

/etc/hostに以下を追記して

# IPは適宜変更してください
192.168.33.10  xhprof.example.jp

ページにアクセスすれば、解析されたデータが確認できます。
https://xhprof.example.jp
f:id:i-plug-develop:20161101164352j:plain

Callgraphのインストール

最後にコールグラフをインストールします。

$ yum install graphviz graphviz-gd

xhprofのconfig.phpの以下のコメントアウトを外す

$ vim xhprof_lib/config.php
/*
$_xhprof['dot_binary']  = '/usr/bin/dot';
$_xhprof['dot_tempdir'] = '/tmp';
$_xhprof['dot_errfile'] = '/tmp/xh_dot.err';
*/

 ↓

$_xhprof['dot_binary']  = '/usr/bin/dot';
$_xhprof['dot_tempdir'] = '/tmp';
$_xhprof['dot_errfile'] = '/tmp/xh_dot.err';

コールグラフ確認

https://xhprof.example.jpにアクセスして、該当データのTimestampをクリック
→ View Callgraphをクリック → 以下のようなコールグラフが表示されればOKです
f:id:i-plug-develop:20161101164247j:plain

まとめ

というわけで、無事ノロマな亀を発見することができました(えらい重たいクエリが...)

こういうボトルネックとなる部分が、視覚的にパッとわかるのは(・∀・)イイネ!!
私みたいな未熟者には大変助かります。神Facebook