Hatena::ブログ(Diary)

Memo

2016-01-11

[] WTForms で QuerySelectMultipleField に default を設定する

WTFormsのSelectFieldで選択値(selected)を保持する方法 - Life is Really Short, Have Your Life!!

WTForms で Select 関連は default を外部から設定できない。

SelectField や QuerySelectField は上記にある。

QuerySelectMultipleField で DB から読み込んだ値をセレクトボックスで複数をデフォルトで設定したい場合は以下のようにすれば行けた。

# -*- coding: utf-8 -*-
from wtforms.ext.sqlalchemy.fields import QuerySelectMultipleField as Base

    """
    QuerySelectMultipleField can only add `default` value at constructor.

    If you want to do like following, you should use this class.

    .. code-block:: python
        form = MyForm(**values)
        #: `users` is `QuerySelectMultipleField` value.
        #: Rows is SQLAlchemy's row list.
        form.users.default = ([u.users.id for u in rows])
    """
    def iter_choices(self):
        if self.allow_blank:
            yield ('', self.blank_text, self.data is None)

        for pk, obj in self._get_object_list():
            if obj.id in self.default:
                yield (pk, self.get_label(obj), True)
            else:
                yield (pk, self.get_label(obj), False)

2016-01-08

[] SQLAlchemy がエラーをはいた

Python で Web アプリケーションを作っていて、ログイン後しばらく放っておいて、他の画面に遷移すると以下のようなエラーが出た。

sqlalchemy.exc.StatementError: (sqlalchemy.exc.InvalidRequestError) Can't reconn
ect until invalid transaction is rolled back 

今まで SQLAlchemy を使ってたけど、初めて遭遇した。

なんだろうこれと思って調べたら、SQLAlchemy の pool_recycle の秒数が MySQL の wait_timeout の秒数より長く設定していためだった。

とりあず pool_recycle の値を wait_timeout と同等にする事で解決。


ちゃんと MySQLチューニングをする際に気をつけないと。

2015-12-31

[] 2015 年振り返り

f:id:heavenshell:20151231132914p:image:w460

OSS480

全て Public Contribution で、今年前半は Pythonbot フレームワークを書いていたから、コミット数が多い。

4ヶ月くらいで、ほぼ機能を作り終えたので、激減してるのが分かる。

思いつきで作り始めたけど、Blinker 使ってイベントを中心に動くようにしたり、割と奇麗に書けたかなーと自画自賛してる。

まぁ自分しか使ってないので、アレだけど。


この bot フレームワークは自社の Slack の一部のチャンネルで元気に動いてるが、Google Image 検索の API が完全に止まったので、Google Custom Search Engine に乗り換えて、制約が厳しいのが辛い。

もっと緩い制約の画像検索が欲しい。


他の OSS の活動としては、細々とメンテしている JSDoc.vimGitHub の star がようやく 100 を超えた。

定期的に Issue が来て、自分以外の人が答えてくれたりするようになった。

またドキュメント周りの拙い英語を直してくれたり、バグフィックしてくれたりと大変ありがたい。

個人的には今の機能で満足しているので、ドラスティックに変更を入れる事はあんまり考えてないが、面白い提案があったら、入れてみるかーくらいの感じ。


他人のプロダクトにコミットしたのは、Lua の Virtualenv みたいなのが上手く動かなかったので、Pull Request 投げた(取り込んでくれてない)、Python の ORM に軽い Pull Request 出した(取り込んでくれた)くらいで、あんまり出来てない。


新しい事

Lua を少し書いてみた。Lua の文法だったり、エコシステムだったり、テスト周りだったりを知れたのは良かった。


Golangツールを書いた。主に仕事で使う(でもあんま使わなかった)と想定したものだった。もう少しさくっと作れるようになりたい。


仕事で JavaJVMチューニング周りをやった。

だいぶ苦労したけど、半年以上全く問題なく動いていて少し自信がついた。


完全にプライベートで GitHub にもあげてないけど、ES6 と React.jsハイブリッドアプリを作ってみようと始めた。

ようやく React.js がほんの少しだけ分かって来た。

まだ React.js で何も考えずに props でバケツリレーをやってる。

ここら辺が辛くなってきたら、Flux を考えるんだろうけど、Flux に関しては落ち着いた起こして下さいという感じ。

ハイブリッドアプリということで、モバイルフレームワークを色々試した。

OnsenUI も良さげだったが、もっと色々そろっている Framework7 をメインにさわっていて、とても良い感じがしている。

OnsenUI は Ver2 から Angular の依存が一部しかなくなったのが素晴らしいが、ログインスクリーンとか、アクションシートとかそういう物が欲しい。

CSS 頑張ればいいんだろうけど、頑張りたくないので、デフォルトでついて欲しい…。


仕事で CoffeeScript を使った。ES6 を触っていたのもあって、そこまで抵抗なくコード読めるし、書けた。

その他

10 月以降は主にお客さんの先に行ってお話を聞くという仕事が多くなってたので、コードを書く時間が激減した。

まぁコードはプライベートで書けば良いので何の問題もないが、モチベーションのコントロールが課題。


あと健康面は少し気をつけたい。秋口にしかも連休中に二回も扁桃腺で倒れたので、ストレスとの付き合い方を考えないといけない。

まとめ

それなりにしんどい一年だった。アウトプットが足らなさすぎる。

来年はもう少し増やして行きたい。

2015-12-12

[] 鬼才デヴィン・タウンゼンド様

この記事は METALバンド Advent Calendar 2015 の 13 日目の記事です。


昨日は Yuya Takeyama さんの好きな Doom Metal のバンドを紹介していく - Born Too Late でした。

Black Sabbath はロニー在籍時代の Heaven And Hell が好きです。

その昔 Dio で Spiritual Beggers と一緒に来日して、Zepp Osaka で Heaven And Hell を見た時に鳥肌たちまくりで、すげーすげーと感動した覚えがあります。


さて自分がメタルを聴きだしたのが 95,6 年くらいだったので、おおよそ 20 年くらい経ち、その中でこの人天才やわーと思うアーティスト・ミュージシャンとは作品やライヴという形で出会ってきましたが、ここ数年で自分が一押しな鬼才アーティストはデヴィン・タウンゼンド様。


スティーブ・ヴァイとともにアルバムを作り、その後自分のバンド Strapping Young Lad で活動し、Strapping Young Lad 解散前からソロ名義や Devin Towsend Project というバンド名義や Casualties of Cool というカントリー調の曲をやるプロジェクトや、Ziltoid the Omniscient というストーリー物(人形劇?)のアルバムを出してます。


Strapping Young Lad や Devin Townsend 名義の Physicist はスピードとアグレッションに満ちたスラッシュメタルをやったり、Punky Bruster ではメロコアをやったり、Terria や Synchestra ではプログレッシブな感じをやり、Ocean Machine ではポップとアンビエントを絶妙にミックスさせたり、普遍的なメロディがとても魅力的なメタルなアルバムを作ったり、一人の人間の中から産み出されたは思えないくらい多彩です。

最近では YouTube でエアコンとジャミングというネタ動画をアップロードしてたりしてます。

D


ライヴでは「ヴァンクーバーから来ました。デヴィン・タウンゼンドです! チンコめっちゃ小ちゃいです! 」とか、ライヴ中にいきなりズボンを脱いで、パンツ丸出しになったり、この前 2 時間でデモを録音できるかっていう企画では、ProTools の操作が上手く行かない時は「このチンコやろう!」を連呼するお茶目なデヴィン様最高!


その中で自分が一番気に入ってるのは、やはりメロディックな面を出している所が大好き。

おすすめなのが、Anneke Van Giersbergen がゲストヴォーカルで参加してる Devin Townsend Project 名義の Addicted。

D

ちなみにこの PV を見て再びデヴィン様熱が復活しました。しかしなんでアニメなんだろうw


同じく Anneke が参加してる Epicloud もおすすめ。

昔 Physicist でやった Kingdom をやり直していて、音が凄くクリアになっているのもおすすめです。

D

D


またてっとり早くデヴィン様の魅力に触れるのはライヴ映像を見るのが一番でしょう。

バックのミュージシャンはスキンヘッド(ベース)、スキンヘッド(ドラム)、坊主(ギター)という髪がない素敵な人たちで、勿論楽器の腕は超一流です。

特にドラマーのライアンさんはジーン・ホグランドや、Soilwork のダーク・ヴェルビューレンが参加した曲もあっさり叩いています。

Retinal Circus

Devin Townsend Presents: Zilto


というわけで、デヴィン様に一人でも興味を持って貰えれば嬉しいです。

なお、日本でデヴィン様の情報は @DevyNerdsJapan さんのアカウントをフォローしておくと最新の情報が手に入ります。

LoudPark来日したけど、フルセットのショウを見たいから来日しないかなー。

2015-11-15

[] Orator という ORM

Orator という ORM があったので試してみた。


サイトには "The Orator ORM provides a simple yet beautiful ActiveRecord implementation. " とある。

ActiveRecord パターンで、PHP の Laravel framework からインスパイアされて、もっと Pythonic にしたって書いてあった。

早速試してみた。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from orator import DatabaseManager, Model

config = {
    'mysql': {
        'driver': 'mysql',
        'host': 'localhost',
        'database': 'dbname',
        'user': 'username',
        'charset': 'utf8',
        'password': 'password',
        }
    }

db = DatabaseManager(config)
Model.set_connection_resolver(db)


class Item(Model):
    __table__ = 'items'


if __name__ == '__main__':
    items = Item.all()
    for item in items:
        print(item.title)

DB のコネクションを作って、モデルにセットして、モデルクラスを定義して、そこから取得してみた。

簡単に取れた。


クエリビルダを使う場合こんな感じ。

rows = db.table('items').where('name', 'foo').get()
    for r in rows:
        print(r['name'])

ORM らしく簡単。


リレーションも勿論出来そうだし、スキーマーのマイグレーションツールも備わってる。

さらには Flask の 拡張も別プロジェクトにあるので、Flask から簡単に使えそう。

Paginator や Cache とかもあったりするので、これ一つで結構な事が出来そう。


ただし utf8 な文字列が入っているデータを取った際に正しく取得できなかった。

色々しらべると、charset を設定しているのに、これが無視されて、PyMySQL でコネクションを確率した際に charset が laten1 になってた。

原因を調べて、Pull Request 出したら、マージしてくれた。

2015/11/15 現在は GitHub の develop ブランチにマージされただけなので、そのうち PyPiアップロードされると思う。


Python で ORM といえば SQLAlchemy がそびえ立っていて、これを使えば何の問題もないけど、ユースケースによっては大げさすぎるというのがある。

単純なサイトだけど、PyMySQL だとちょっとだるくて、SQLAlchemy だと大げさすぎるという感じの場合に、Orator 使えば良さそう。

2015-10-23

[] Flask-WTF のファイルアップロード

メモ。というかドハマりした。


Flask-WTF を使ってファイルをアップロードする際、こうやって書いたらファイルのみ受け取れなかって ??? となった。

from flask_wtf.file import FileField


class PhotoForm(Form):
    photo = FileField('Your photo')


@app.route('/upload/', methods=('GET', 'POST'))
def upload():
    form = PhotoForm(request.form)
    if form.validate_on_submit():
        filename = secure_filename(form.photo.data.filename)
        form.photo.data.save('uploads/' + filename)
    else:
        filename = None
    return render_template('upload.html', form=form, filename=filename)

問題は

form = PhotoForm(request.form)

ここで、正しくは

form = PhotoForm()

だった orz


通常のフォームは request.form が必要だけど、ファイルアップロードの時は不要。

2015-10-11

[] SQLAlcyemy で repr を自動で

メモ。


SQLAlchemy でモデルクラスを定義していて、__repr__ を毎回定義するのがダルい。

かといって定義しないと、デバッグ時(主にプリントデバッグ)に中身が出ないのも困る。

# -*- coding: utf-8 -*-
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship
from db import Base

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String(50), unique=True)
    email = Column(String(120), unique=True)

    def __init__(self, name=None, email=None):
        self.name = name
        self.email = email 

    def __repr__(self): 
        # これを毎回書きたくない
        return 'User(id={0}, name={1}, email={2})'.format(
            self.id, self.name, self.email
        )

方法はないかと思ってググったら、以下がヒットした。

( f o o b a r . l u ) » Blog Archive » Automagic __repr__ for SQLAlchemy entities with primary key columns with Declarative Base.

試してみたけど、プライマリーキーが取れるだけだった。

次にヒットしたのが、sqlalchemy - Python __repr__ and None - Stack Overflow


真似してみた。

# -*- coding: utf-8 -*-
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base


class RepresentableBase(object):
    def __repr__(self):
        """Dump all columns and value automagically.
    
        This code is copied a lot from followings.
        See also:
           - https://gist.github.com/exhuma/5935162#file-representable_base-py
           - http://stackoverflow.com/a/15929677
        """             
        #: Columns.
        columns = ', '.join([
            '{0}={1}'.format(k, repr(self.__dict__[k]))
            for k in self.__dict__.keys() if k[0] != '_'
        ])
        
        return '<{0}({1})>'.format(
            self.__class__.__name__, columns
        )

engine = create_engine('sqlite:///test.db', convert_unicode=True)
db_session = scoped_session(
    sessionmaker(autocommit=False, autoflush=False, bind=engine)
)

Base = declarative_base(cls=RepresentableBase)
Base.query = db_session.query_property()


def init_db():
    Base.metadata.create_all(bind=engine)

モデル。

# -*- coding: utf-8 -*-
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship
from db import Base

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String(50), unique=True)
    email = Column(String(120), unique=True)

    def __init__(self, name=None, email=None):
        self.name = name
        self.email = email


class UserImage(Base):
    __tablename__ = 'images'
    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey('users.id'))
    image = Column(String(120), unique=True)
        
    user = relationship('User', backref='images',
                        primaryjoin='User.id==UserImage.user_id',
                        lazy='joined')

    def __init__(self, user_id=None, image=None):
        self.user_id = user_id
        self.image = image

使う側。

from sqlalchemy.orm import joinedload
from db import db_session, init_db
from models import User, UserImage
        

if __name__ == '__main__':
    init_db()

    user = User(name='foo', email='foo@example.com')
    db_session.add(user)
    db_session.flush()
    print(user)
    
    image = UserImage(user_id=user.id, image='/path/to/image')
    image2 = UserImage(user_id=user.id, image='/path/to/image2')
    db_session.add_all([image, image2])
    db_session.flush()
    db_session.commit()
    
    data = db_session.query(User).options(joinedload('images')).all()
    print(data)

結果。

$ python app.py
<User(email='foo@example.com', id=1, name='foo')>
[<User(images=[<UserImage(id=1, user_id=1, image='/path/to/image')>, <UserImage(id=2, user_id=1, image='/path/to/image2')>], email='foo@example.com', id=1, name='foo')>]

ちゃんと取れた。

関連付けをしていても関連先のもちゃんと表示してくれる。