Django REST FrameworkのフィールドでJSONを扱う

DjangoのモデルにTextFieldでJSON文字列を保存しておき、APIDjango REST Frameworkで提供する例。

JSONデータを保存して、読み込み時にもJSON形式のまま提供したかった。

restframeworkのシリアライザのFieldクラスを継承し、JSONを扱うフィールドを定義して使う。

コード

app1/models.py:

from django.db import models


class Model1(models.Model):
    class Meta:
        ordering = ['pk']

    data = models.TextField("JSONデータ", null=True, blank=True)

app1/serializers.py:

import json
from rest_framework import serializers

from .models import Model1


class JSONDataField(serializers.Field):
    """JSONテキストのシリアライザ,デシリアライザフィールド
    """
    def to_representation(self, obj):
        if obj:
            return json.loads(obj)
        return None

    def to_internal_value(self, data):
        return json.dumps(data, indent=2)


class Model1Serializer(serializers.ModelSerializer):
    data = JSONDataField()

    class Meta:
        model = Model1
        fields = [
            'id', 'data'
        ]

app1/views.py:

import coreapi
import coreschema
from rest_framework import viewsets
from rest_framework.schemas import AutoSchema

from .serializers import Model1Serializer
from .models import Model1


class Model1Schema(AutoSchema):
    def get_manual_fields(self, path, method):
        # 作成, 更新だけdataフィールドの定義を差し込む
        if method not in ['POST', 'PUT', 'PATCH']:
            return []
        return [
            coreapi.Field(
                "data",
                required=False,
                location="form",
                schema=coreschema.Object()
            )
        ]


class Model1ViewSet(viewsets.ModelViewSet):
    serializer_class = Model1Serializer
    queryset = Model1.objects.all()
    schema = Model1Schema()

REST Frameworkで自動生成されるAPIドキュメントで扱えるように、schema定義を入れています。

app1/urls.py:

from django.urls import path

from rest_framework.documentation import include_docs_urls
from rest_framework.routers import DefaultRouter

from . import views

router = DefaultRouter()
router.register(r'model1', views.Model1ViewSet, base_name='model1')

urlpatterns = [
    path('docs/', include_docs_urls(title='app1 API', public=True)),
] + router.urls

サンプルコード一式

動作例

list: f:id:nullpobug:20180408175330p:plain

create: f:id:nullpobug:20180408175335p:plain

PythonでUNIXドメインソケットを使ったHTTPサーバーとクライアントを作る

Pythonでプロセス間通信をしたい、プロトコルはHTTPで、データフォーマットはJSON。なるべく1つのスクリプトファイルでサーバーやクライアントを提供したい。

こんな感じの要件。

元々Flaskが使われてるプロジェクトだったので、Flaskで全部やればいいかーと思ってました。

しかし、WerkzeugがUNIXドメインソケットに対応していなかったので、Waitressを使うことにしました。

クライアント側はRequrestsを使おうとしたけど、そちらも追加のコードが必要でした。

これはrequests-unixsocketという都合のいいパッケージがあったので使いました。

Pythonのバージョンは3.6。

ソースコード

requirements.txt

flask
waitress
requests
requests-unixsocket

server.py

from waitress import serve
from flask import Flask, jsonify

app = Flask(__name__)


@app.route('/endpoint/')
def index():
    return jsonify({'result': 'OK'})


def main():
    serve(app, unix_socket='/tmp/app.sock')


if __name__ == '__main__':
    main()

client.py

import requests_unixsocket


def main():
    session = requests_unixsocket.Session()
    resp = session.get('http+unix://%2ftmp%2fapp.sock/endpoint/')
    print(resp.json())


if __name__ == '__main__':
    main()

実行結果

server

(venv) $ python server.py
Serving on http://unix:/tmp/app.sock

client

(venv) $ python client.py
{'result': 'OK'}

便利ですね。

『エキスパートPythonプログラミング 改訂2版』を読みました

『エキスパートPythonプログラミング 改訂2版』のレビューのお手伝いをしたので見本誌をいただきました。

エキスパートPythonプログラミング改訂2版

エキスパートPythonプログラミング改訂2版

雑感

  • 対象はPythonにある程度慣れてる人向け
  • Pythonを使いこなすための知識がいろいろ
    • クラスやデータ構造をうまく使うとか
    • 並行処理とか

本書で学べるPythonの内容

  • Pythonでのクラス、オブジェクト指向プログラミング
  • どのようにPythonモジュールを構成していくか、パッケージを作るか
  • C言語などでのPythonモジュール作成方法
  • パフォーマンスチューニングの方法
  • Pythonでの並行処理、async、await構文

など。Pythonの入門的な解説はなし。

まとめ

本書は入門書ではありません。Pythonをより使いこなすための知識を得られる内容になっています。

Pythonにある程度慣れてきた人に、次の一歩としてオススメしたい本です。

『いちばんやさしいPythonの教本』を読みました

PyQの関連で献本いただいたので『いちばんやさしいPythonの教本』を読みました。前職の同僚が執筆した本です。

いちばんやさしいPythonの教本 人気講師が教える基礎からサーバサイド開発まで (「いちばんやさしい教本」シリーズ)

いちばんやさしいPythonの教本 人気講師が教える基礎からサーバサイド開発まで (「いちばんやさしい教本」シリーズ)

雑感

  • 用語説明が丁寧
  • 図版が多くてわかりやすい
    • 注釈も多いですが、読みづらくならないよう、レイアウトされていて良い

「いちばんやさしい」とタイトルにあるとおり、プログラミングの知識なしで読み始められるような内容になっていました。

本書で学べるPythonの内容

  • Pythonのインストール、開発環境の整備
  • Pythonの文法
    • クラスは含まない
  • Pythonスクリプトの作り方
    • 複数のモジュールにまたがるプログラムの作成
  • サードパーティ製モジュールの使い方
  • Webアプリケーション作成

クラスやオブジェクト指向プログラミングの解説はされていません。 入門書だし、ボリュームの都合上、入り切らないでしょうし、仕方ないかと思います。

本書で入門し、足りなければ他の書籍も読んでみるのが良いですね。 本書のChapter10にも他の本の紹介や、勉強の仕方が説明されています。

まとめ

図版や注釈が多く、見やすくレイアウトされているため、はじめてプログラミングする人でも読みやすい内容になっています。

「いちばんやさしい」にふさわしいPythonの本ですね。

DjangoフレームワークとVue.jsを使ってアプリケーションを作る

DjangoフレームワークとVue.jsでアプリケーションを作る例として、テキストを編集保存するシンプルなノートアプリケーションを作ってみました。

github.com

f:id:nullpobug:20180318185136p:plain

Djangoのサーバーサイドレンダリングを使いつつ、Vueを組み合わせる一例として参考になればよいかなと。

Django側はDjango REST FrameworkでAPIを用意していて、意図的にテストコードは用意してません。

JavaScriptのほうは、Vue.jsを使いつつ、なるべくテストコードを書きやすいように作ってみました。

その他詳細は、リポジトリにREADMEがあるので参照してみるとよいかと。

コードに説明のコメントなども入れています。

Windows上のVirtualBox共有フォルダでシンボリックリンクを有効にする

ホストOSをWindowsVirtualBox上のゲストOSをLinuxとして、VirtualBoxの共有フォルダ機能を使った場合、Linux側で共有フォルダ内にシンボリックリンクを作ろうとすると、デフォルトでは許可されず、エラーが発生します。

vagrant@ubuntu-xenial:/vagrant$ ln -s test.txt test2.txt
ln: シンボリックリンク 'test2.txt' の作成に失敗しました: プロトコルエラー

Pythonのvirtualenvや、Node.JSのnpmを使うときにシンボリックリンクが使えないと不便なので、これを解消します。試したのはWindows 10、VirtualBox 5.2.8、Vagrant 2.0.2

※2018/3/12更新: 最初はWeb検索で出てきた情報で試してて、うまくいったように見えたので、その手順を記載していましたが、不要な手順があるなどの指摘をもらったので、再調査して記事を大きく書き直しました。

VirtualBoxの共有フォルダとシンボリックリンク

そもそもVirtualBoxは、どうやってWindows側にシンボリックリンクを作るかを調べました。VirtualBoxソースコードが公開されていて、コードも整理されているので簡単に見つかりました。

というわけで、Windowskernel32.dll にある CreateSymbolicLinkW 関数を使っています。

また、setextradata VBoxInternal2/SharedFoldersEnableSymlinksCreate/%s の設定でシンボリックリンクの有効、無効が切り替わります。

Windows10でシンボリックリンクの作成を許可する

Windows 10の場合、シンボリックリンクを作成する権限はデフォルトではAdministratorグループのみになっています。

「ローカル セキュリティ ポリシー」-「ローカル ポリシー」-「ユーザー権利の割り当て」-「シンボリック リンクの作成」に一般ユーザーのグループ(Users)を追加することで、一般ユーザーでもシンボリックリンクを作成できるようになります。

f:id:nullpobug:20180312020620p:plain

http://f.hatena.ne.jp/nullpobug/20180312020620

これにより、 CreateSymbolicLinkW 関数でシンボリックリンクを作成できます。

VirtualBoxの設定

VirtualBoxで共有フォルダのシンボリックリンクを有効にするため、設定をVBoxManageコマンドで変更します。

VBoxManageコマンドはVirtualBoxディレクトリに入っています。PATHが設定されていない場合は、直接ファイルを指定して実行します。

PS C:\Users\tokibito> & 'C:\Program Files\Oracle\VirtualBox\VBoxManage.exe' setextradata VM名 VBoxInternal2/SharedFoldersEnableSymlinksCreate/共有フォルダ名 1

Vagrantの場合

Vagrantでは共有フォルダは、デフォルトでVirtualBoxシンボリックリンク設定(VBoxInternal2/SharedFoldersEnableSymlinksCreate/%s)を有効にしてくれるので、Windowsのポリシーの変更以外は特に追加の設定は不要でした。

実行結果

vagrant@ubuntu-xenial:/vagrant$ ln -s test.txt test2.txt
vagrant@ubuntu-xenial:/vagrant$ ls -l test2.txt
lrwxrwxrwx 1 vagrant vagrant 0  2月 28 01:11 test2.txt -> test.txt

2018年

年初なので今年やりたいこととか考えて整理しておく。 まず去年のを見直す。

2017年 - 偏った言語信者の垂れ流し

見直してみると、2017年に書いたことはあんまりやれてない。 去年の後半は仕事とかで余裕がなかったかな。

今年はもうちょっと具体的な内容にしてみようか。

  • 家にある不要なものを捨てる
    • 数年使ってないものとか使いそうにないものは捨てる
  • 畑は、各季節ごとに収穫できるものを計画的に植える
    • 半年先ぐらいまでの計画を考える
  • 山歩きと街歩き(散策)をする
    • 行ったことある山と行ったことない山、ルートをいくつか
    • 関東圏の観光スポットや歴史的な場所などまだ行ったことのないところとか
  • お金周りは、資産形成の計画や保険を見直す、低リスクな範囲で色々試して知見を得る
  • 少なくとも二ヶ月に1回程度の頻度で車を運転して慣れる