Make組ブログ

Python、Webサービスや製品開発、ライブラリー開発についてhirokikyが書きます

Using .raw method of Django's QuerySet

Using .raw method of Django’s QuerySet

Today, I show you to use .raw method of Django’s QuerySet. The method is powerful and it can manipurate data in DB even if a column is not appear in Model’s field.

Of cause you can choice to use executing raw query by db connection directory. But, using raw method of QuerySet is more comfy. The method allow you to map the values in DB to the objects manually.

Ok, now let me show you a example. Consider a model calss, named Post, like this:

class Post(models.Model):
    title = models.CharField(max_length=255)
    body = models.CharField(max_length=255)

The model is simple and common what in like everyday we write. And then, try to change the schema of it directory:

sqlite> ALTER TABLE demoapp_post ADD COLUMN "slug" varchar(255);
sqlite> .schema demoapp_post
CREATE TABLE "demoapp_post" (
    "id" integer NOT NULL PRIMARY KEY,
    "title" varchar(255) NOT NULL,
    "body" varchar(255) NOT NULL,
    "slug" varchar(255));

just now, I added a column named ‘slug’. The column and model fields have a difference now. This ‘slug’ appears in sqlite db column, but not in the model.

And try to insert a row:

sqlite> INSERT INTO demoapp_post ("title", "body", "slug") VALUES ("test", "test body", "test slug");
sqlite> SELECT * FROM demoapp_post;
1|test|test body|test slug

Then let’s consider how we can get the value of slug (‘test slug’).

Use .raw method

The easiest way is ‘adding a field to the model and migrating the existed DB’. Yes, I know. but, sometime we should get a value from DB even if the column is not in the model fields.

Then, you might want to use raw method?

We can write a SQL directory as a argument to raw method. and the return value of the SQL will be mapped to a Model called the raw method, like this:

>>> post = Post.objects.raw("SELECT * FROM demoapp_post")[0]
>>> post.title
u'test'
>>> post.body
u'test body'
>>> post.slug
u'test slug'
>>> post.nothing
Traceback (most recent call last):
 File "<console>", line 1, in <module>
AttributeError: 'Post' object has no attribute 'nothing'

Yeah! the value of ‘slug’ was showed up. In common way, we can’t get the vaule..:

>>> post = Post.objects.all()[0]
>>> post.title
u'test'
>>> post.body
u'test body'
>>> post.slug
Traceback (most recent call last):
 File "<console>", line 1, in <module>
AttributeError: 'Post' object has no attribute 'slug'

Mapping the attribute more flexible

And then, by specifying the ‘translations’ attribute, we can change the mapping from DB value to Model attribute.

Ok next, let’s try to get the value of ‘slug’ column, through ‘urlslug’ attribute of a model:

>>> post = Post.objects.raw("SELECT * FROM demoapp_post", translations={'slug': 'urlslug'})[0]
>>> post.slug
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'Post' object has no attribute 'slug'
>>> post.urlslug
u'test slug'

aw, it’s spookey, though.

(I checked above codes with Django 1.6)

Python3.4のSingle-dispatchで遊んでみた - Python Advent Calendar 2013

Python3.4のSingle-dispatchで遊んでみた - Python Advent Calendar 2013

Python Advent Calendar 2013 の 1 日目を担当します、 @hirokiky です。 昨年 に引き続きPythonAdventCalendarを主催しています。

ちなみに今年は現時点であと 4 人参加者が足りません!ぜひご参加ください

さて、今年の Python Advent Calendar のテーマは ‘Not Web’ ということなので、 Web に限らない話を書きます。

つい最近の11月24日に Python 3.4 の Beta 1 がリリースされました。 Python 3.4 b1 には無事 ensure-pip も入り、いよいよ Python 3 感が増してきました。 そんなところですが、ここで Python 3.4 から入る singleddispatch で遊んでみました。

single-dispatchって何?

singleddispatch は functools の一つで、第一引数の型に応じて処理を変更する generic function を作るものです。

単純な例で試してみます:

from functools import singledispatch

@singledispatch
def fun(arg):
    return 'default'

## Registering behaviors to correspond to each types

@fun.register(int)
def fun_int(arg):
    return 'int'

@fun.register(list)
def fun_list(arg):
    return 'list'

assert fun(3) == 'int'
assert fun([]) == 'list'
assert fun('str') == 'default' # str type is not registered.

assert fun_int('dummy') == 'int'
assert fun_list('dummy') == 'list'
assert fun(object()) == 'default'  # Using 'instance of object' to test the default behavior.

ポイント:

  • singledispatch によって generic function を定義
  • .registerによって、型と対応する処理を登録
  • 通常の関数のように generic function を呼び出す

アンチパターン

さきほどあげた例では少し簡単すぎるので、利点が伝わりにくいかもしれません。 なのでここで、アンチパターンをあげておきます:

def fun(arg):
    if isinstance(arg, int):
        return 'int'
    elif isinstance(arg, list):
        return 'list'
    else:
        return 'default'

assert fun(1) == 'int'
assert fun([]) == 'list'
assert fun('str') == 'default'

ダメなポイント:

  • 新しい型と対応する処理を後から追加できない
  • 各型に応じた処理を取り出せない (先の例でいう ‘fun_int’ などを直接テストできない)
  • 見難い

などですね。

他にもいくつか挙動を試していますが、長くなるので気になる人は Githubリポジトリ にあげてるのでそちらを参照してください。

実用例を考えてみた

さてこの singleddispatch 、たしかに面白いですが何に使えるでしょうか。 一つ考えてみたのは 「任意の型で返り値を返す関数たちについて、返り値を共通の型で包む」 というものです。ちょっと自分で言っててもよく分からないので、例を考えます。

チャットするロボットを考えます。人間とロボットはMessageというオブジェクトでやりとりするとしましょう。 ロボットは単なるcallableで、Messageオブジェクトを受け取りMessageオブジェクトを返します。 ただ実装上、このロボットが返す値をいちいちMessageオブジェクトにしてやるのは面倒なので、 ロボットから返す値をMessageオブジェクトに変換する処理を挟んでやります。 この「何らかの型」 => 「Messageオブジェクト」の変換処理をgeneric functionとして持つわけですね。「共通の型」というのがこのMessageオブジェクトです。

さてまずはロボットの実装に必要な、ライブラリとしての処理を実装します。

  • Message: ロボットとのやりとりに使うオブジェクトのクラス
  • generate_message: 各型 => Messageに変換するgeneric function
  • as_robot: 関数をロボットとして定義するデコレーター
class Message(object):
    """ Messages to communicate each robots.
    """
    def __init__(self, body, **metadata):
        self.body = body
        self.metadata = metadata

    def __str__(self):
        return '''\
{self.body}
* metadata: {self.metadata}
'''.format(self=self)

@singledispatch
def generate_message(arg):
    """ Creating Message object for each types.
    """
    raise TypeError('Unexpected type')

@generate_message.register(str)
def str_to_message(arg):
    return Message(arg)

@generate_message.register(dict)
def dict_to_message(arg):
    body = arg.pop('body')
    return Message(body, **arg)

def as_robot(func):
    def wrapped(*args, **kwargs):
        ret = func(*args, **kwargs)
        return generate_message(ret)
    return wrapped

さてこれでロボットを実装する準備ができました。 ここまでをライブラリ、フレームワーク側から提供されるべきものと想定しています。 以下はそれを利用した、ユーザー側が書くべき処理の例です:

@as_robot
def antique(message):
    return "Good morning, Master Ren."

@as_robot
def neomodel(message):
    return {'body': "I'm here.",
            'enjoyment': 1}

if __name__ == '__main__':
    print('antique::', end=' ')
    print(antique('dummy message'))
    print('neomodel::', end=' ')
    print(neomodel('dummy message'))

実装できました。

antique関数では文字列を直接返し、neomodel関数では辞書を返しています。 各関数はas_robotというデコレーターで包まれているので、戻り値がMessageオブジェクト で共通になります。

実行してやるとこんな答えが返ります:

antique:: Good morning, Master Ren.
* metadata: {}

neomodel:: I'm here.
* metadata: {'enjoyment': 1}

まぁこんなかんじで、任意の型 => 共通の型への変換処理を作るのにも使えるのではないか という例でした。 もちろんロボット関数がMessageオブジェクトを返した場合や、後から変換処理を追加する ことも考えられます。これもアップロードしてあるファイルから見てみてください。

ただこの例の場合as_robotデコレーターを外せないので、純粋な関数としての テストが難しいです。そこはas_robotデコレーターを取り外し可能にするなどして 対応するのが良いかもしれません。

まとめ

  • singleddispatch 面白い
  • 任意の型 => 共通の型 への変換などに使えそう

小さいながらも面白い機能で、とくにフレームワークやライブラリを提供するときに 使えそうな印象です。

遊びで書いたコードはここにおいていますので、より詳しくは読んでみてください:

以上です。2日目は露木さん(@everes)にお願いしたいと思います。

何かを作り続けるのはどうすればいいのだろう

何かを作り続けるのはどうすればいいのだろう

ものを作るって、ただ一発何かを作るだけじゃないと最近よく思う。 何か作ったらそれをより良くするため作りつづけたり、多くの人に 使ってもらうために広めたりする必要があると思う。

私が今、頭で考えて言っている「作る」っていうのは、 自己探求とか表現とかそういうものとちょっと違う。 広く使われていて便利なものを生み出すのはどうすれば良いのかな、という 疑問だったりする。 自分のなかにおいて探求とか表現とかいうなら、無人島にいてもコードは書ける。 そんな状況でもコードを書くのかと聞かれたらたぶんYesと答えるんだけど、 そこにあるコードはそれ以上でも以下でもないものではないかと、 今みたいに虚しくなるときがある。

自己満足だけでない良くできたコードを作っていくのは どうしたらいいんだろう。 よく「プログラミングをはじめよう」や「とりあえず何か作ってみよう」 という啓蒙があるけど、そんな話はもううんざりである。 どうすればものを作り続けてより良いものにしていけるかが知りたい。

Twitterで @chichimotsu さんが:

「どんどんいろんなもの作って、それをさらに繋げて行けたらいいよね。」

と言ってくれて、これはなかなか良いなと思った。 自分のなかでは結構さっさと飽きてしまうのだけど、それだけで終わらさない ように浮気をしつつも全体として繋がりをもたせておくのは良いかもしれない。

今日 Uiro framework 0.2 をリリースしたのだけど、何かリリースした後は どうにもこんな気分になる。平たく言うと飽きたのかもしれない。

Getting the definition order of class attributes in python

Getting the definition order of class attributes in python

Same question was in StackOverFllow, but the answer was not so soft on me.

It gave me a some hints, but it actually says ‘Watch a code’. Ok, so I read the code and understood that behavior, I will write that description here.

Why is definition order necessary

The best example is on Form libraries. The definition order will affect to rendering order directory.

Consider on a suprious form library, like this:

class MyForm(Form):
    name = StringField()
    text = StringField()

and it should be rendered that the first place is name and the second text like this oreder:

<input value='name' />
<input value='text' />

Of cause, general form libraries consider the definition order, such as Djnago Form, deform (actually, colander’s behavior).

On my case, I should handle it on creating Uiro framework, definition views in controller.

Answer

To handle the order, you should place a counter. The counter will be increased on each constraction of orderd attributes. And then, each attributes stores that counter value to it’s own.

>>> import itertools
>>> class Field(object):
...     _counter = itertools.count()
...     def __init__(self):
...         self._order = next(Field._counter)
... 
>>> class Form(object):
...     name = Field()
...     text = Field()
... 
>>> Form.name
<__main__.Field object at 0x7f0abfb26250>
>>> Form.name._order
0
>>> Form.text._order
1

Ok, seems good. Then, apply this practice on writing metaclass:

>>> class FormMetaClass(type):
...     def __new__(cls, name, base, attrs):
...         new_class = super(FormMetaClass, cls).__new__(cls, name, base, attrs)
...
...         fields = [(name, value) for name, value in attrs.items()
...                   if isinstance(value, Field)]
...
...         # sorting manually corresponds to the definision order of Fields.
...         fields.sort(key=lambda e: e[1]._order)
...
...         new_class.fields = fields
...         return new_class
... 
>>> class Form(metaclass=FormMetaClass):
...     name = Field()
...     text = Field()
... 
>>> Form.fields[0]
('name', <__main__.Field object at 0x7f0abfb26410>)
>>> Form.fields[1]
('text', <__main__.Field object at 0x7f0abfb26490>)

sweet, the definition order didn’t lost. In __new__ method, the fields before sorted, the order of Fields is not considered in fields, because the attrs is just a dictionary. so we should apply _oreder attribute to Field and re-consider the order manually using that _order.

I used this tips on this change, check it out.

アウトプットとはなんだったのか

アウトプットとはなんだったのか

よくある言葉に「インプットすればアウトプットしろ」という啓蒙がある。

感じるのは、言われているアウトプットとはブログ記事として出力されたものを 意味する場合が多いということ。 加えてカンファレンスや勉強会での発表であったり、 どこかの雑誌への連載や書籍の出版などがある。

共通して感じるのはそれら「アウトプット」が指すものは、 ある程度体系化された情報であるということ。 情報の受取り手に対して明確に「こうすればこうできる」という提示できる もの。入門、ステップバイステップ、事例、失敗談、そういった情報を指す場合が 大半なのではないかということ。

これは主観的な感想なので、そう思わない人はいて当然だけど、 どこか「アウトプットしよう」という話を聞くと疑いたくなる。

得た情報を他に伝えたり、回帰する方法は他にあるんじゃないかと。

ソースコードで表してみる

文章で説明しなくても、ソースコードに書けばいいんじゃないか。

「こんな問題があった」ならその問題を解決するようコードを修正すればいい。 「こんなふうに使うと便利」ならその方法で作ったものを公開すればいい。

根本的に問題を解決できたり、読み解くことで参考にできたりを 実装として回帰すればいいんじゃないか。

ノブの上にノブを乗せる方法や、ノブを彩色する方法や、固着したノブを こじ開ける方法ではなくて、誰でもすんなり開けれるドアノブを作ってやる。 それが誰しもが求めてるはずの、正しいことなんじゃないか。

もちろん状況によっては「正しい」解を求めるべきじゃないときもある。 固着したノブを開ける方法が必要なときもある。 でもそれは実はとっっっても下らない話で、せめて自分の制限のない時間ぐらいは 本質的に求めているドアノブについて考えるべきなんじゃないか。

例えばWebフレームワークの提示する記述方法が貧弱故にテストしにくいとして、 その解決方法はWebフレームワークから提供されるべきだと思う。

FlaskやDjangoにおいて、Viewに適応されたデコレーターはユニットテスト時に 邪魔でしかないわけだけど、Pyramidはその問題を解決している。 Djangoにおいて厄介であったテスト時のsettingsの置き換えは後のバージョンで 取り込まれたoverride_settingsによって対処された。

Pythonにおいてサーバーとアプリケーションを切り離すのにWSGIは役立っているし、 厄介であったパッケージングの問題も解決に向かっている。

多くの人が考えて苦労してどうにかしてなんとかして対処法を体系だてて 解説してきたことは、実はその手にあるノブを修理することでアッサリ 解決するんじゃないか。魔法みたいに。

まずはドアノブは誰かに提供されるだけのものじゃなくて、 自分でも修理できるものだと常に意識して、毎度本質に気づかないといけない のかもしれない。

そのソースコードの意義と説明

実装でどうにかするというのは素晴らしいのだけど、それだけだと悪い場合がある。 その実装の説明が必要な場合だ。 ソースコードに表すだけだと人にはどう考えても伝わりにくい。 ガイドとしてそれの意義、使い方を説明する必要がある。

何より厄介なのは、実装だけするということに対して直感的に「悪い」 という感情を自分自身が持っているということ。 とくに私の場合は「ちゃんとやってない」という気持ちがフツフツと湧いて出る。 docstring、README、long_descriptionやドキュメントが無いと、ことさら「悪い」という気持ちになる。

それはプログラミングをすると絶対付きまとってくる感情で、 自分の得た知見を多くの人々に回帰できていないような感情になる。

でもそれってどうなんだろう。 別に吐いて捨てたコードがあって何が悪いんだろう。 もちろん成果として求められる場合は説明も含めて成果であろうけど、 少なくとも好き勝手やってる「アウトプット」にそれが必要なんだろうか。

「情報として体系化されてない」状態を「悪い」と思ってしまうのは 1ユーザー、1フリーライダーとしての感覚が大きいんじゃないか。 「1フリーライダー」としての感覚を適応すると、そういった説明のない ソースコードには残念な気持ちにはなる。 もっと俺は楽したいのに、もっと俺は楽できるはずなのに、と思う。

でもそれは、自分でもわかってるけど甘い考えなんじゃないかな。 そのソースコードを参考にしたりパクったりすることで十分使うことはできる し、公開されてるだけでもありがたいものだ。 もともと書いた人間が説明してやる義理なんてないし、公開する習慣がある だけでも感動ものなんじゃないか。

そんなに説明がないことが気に入らないなら自分で理解してそれをすればいい。 これは単なる地ならしだけど、もちろんこれも賞賛されるべき情報だ。

ソースコードだけというのは体系化された情報ではない。 整備された「高速道路」ではないけど、でもこれも存在するアウトプット だと捉えたい。

思った

全体として無駄な時間が削減されているかということに注目したい。

荒いアウトプットは、技術的に成熟してない領域に近づくにつれて必要になっていくようにも 感じる。 どのみちそんなのは多くの人間が求めてる情報ではないので丁寧に整備しても見合わない

結局アウトプットとはなんなのだろう。 ORMやアクティブレコードだけがモデルを指さないように、 ブログ記事みたいな、ある程度体系化された情報だけがアウトプットを指さない と思いたい。

自分が得た情報を回帰する方法はたくさんあって、その情報にとって最も効率の いい方法を選択ればい良いだけの話なのかもしれないけどね。

PasteScript空騒ぎ

PasteScript空騒ぎ

PasteScript の話。

PasteScriptって?

アプリケーションに必要なコマンドを作る地盤を提供してくれるものです。 PasteScript 自身が提供するものでは、テンプレートからアプリケーションを作成する コマンドがあります:

paster create

テンプレートを作っておけばアプリケーションがさくっとできます。

この説明だけだとなんじゃそりゃという感じですが、ここで PasteDeploy も紹介します。

PasteDeployWSGIアプリケーションの構成を設定ファイルから指定できるものです。 例えばDBの設定やLoggingの設定をファイルに記述して、その設定を元に アプリケーションを構築、起動できます。

この PasteDeployPasteScript を併用することで以下のようなコマンドで 簡単にWSGIアプリケーションが起動できたりします:

paster serve

この serve コマンドも PasteScript の提供するもので、 PasteDeploy の 機能を使って簡単にWSGIアプリケーションを構築、起動できます。 (必要な設定はdevelopment.iniのようなiniファイルに書いておきます)

WSGIアプリケーションで開発するにも Django でいう management command とか startapp が欲しくなりますが、まぁ PasteScript はそんなとこです。

PasteScript空騒ぎ

その PasteScriptWSGIアプリケーションやWebフレームワークで広く使われており デファクトスタンダードといっても良いくらい有用なものですが、一つ大きな問題がありました。

Python3 に対応していないということです。(あぁレガシー)。

で一番困るのは PasteScript を使っていた各Webフレームワークたちです。 Webフレームワークも「よしPython3に対応するか」と思うわけですが、 依存するパッケージがPython3に対応していないと話になりません。

ここで各フレームワークが頑張って脱 PasteScript を模索します。

Pyramid はその内部に PasteScript を取り込み/修正し、 pcreate などの コマンドを提供しました(Python3対応をしている PasteDeploy はPyramid1.4の現在でも使われています)

Turbogearsgearbox を用意しました。これは PasteScript の代替になる パッケージで、 Python3 でも動作します。

いっぽうDjangoPasteScript に依存せず独自のmanagement commandという地盤と project/application templateのしくみを提供していたので、全く関係ありませんでした。

gearboxおすすめ

さてさて PasteScript が使えない今、WSGIアプリケーションを作る際には どうしたものでしょうか。

gearbox を使いましょう。

これはTurboGears2がPython3対応する際にできたパッケージですが、TurboGearsに無関係な WSGIアプリケーションでも使えます。ついでに PasteDeploy に依存して serve 用の コマンドも直接提供してくれます:

gearbox serve

gearbox はどのWSGIアプリケーションでも使えて素晴らしいです。 WeiWei というWebフレームワークレス なWSGIアプリケーションを最近書いたのですが、これでも使わせてもらってます。

ついでにScirptとかDeployとかややこしいのをマルっと一つにしてるあたりも分かりやすいです。

gearbox 素晴らしい。WSGIアプリケーション+Python3を書くならこれを使うのを薦めます。

PasteScriptのPython3対応

さてPython3非対応でお騒がせした PasteScript ですが、 つい最近今年の 9 月にようやく Python3 に対応したようです!!

すごい!!やった!!!!

と思いきや、残念なことに 2to3 を前提としています。

まぁこれは使いたく無いですね。 classifierも書き換えられてないしインストール時に2to3がかかるようにもしてないようです。 (gearbox は現時点でまだ0.0.2ですが Python3 でも使えるいいこですよ٩(๑❛ᴗ❛๑)۶)

このマージを見つけたときは興奮しましたがちょっと違う。 PasteScript をPython3対応をちゃんとさせたいんだという人は aodagさんのプルリクエストを修正/レビュー/応援すると良いと思います。

私は gearbox の恩恵に甘えます。

まとめ

gearbox 使いましょう。

余談

世の中に入門記事ばっかり溢れてもつまらないので、ちょっとした小ネタを書きました。 パッケージの歴史の話 とかも結構面白い ので、こういうどうでもよくないどうでもいい記事が増えればいいと思います。

(PasteScript や Pyramid のPy3対応については人から聞いた話も多いので 間違ってたら教えてください。たまに PasteDeploy と逆に言っちゃうし )

Pythonにおける「許されざる悪事」を避けるために

Pythonにおける「許されざる悪事」を避けるために

許されざる悪事というものが存在する

モジュールを import するだけでグローバルな値が設定されるというもの。

「import の順番に依存した処理ほど不愉快なものはない。こういった依存性を持つ処理は非常に脆弱で、ちょっとしたことですぐエラーとなってしまい、メンテナンスしにくいコードになってしまうものなのである。」

ぁっぉ

やってみよう

importに依存しない処理を書いてみましょう:

# In mymodule.py

hoge = None

def setup_hoge():
    global hoge
    hoge = 'hoge'

としてアプリケーションの設定をする処理のうちにsetup_hogeを呼び出してやります。 (まぁ paste.app_factory に指定する main 関数とかそんなとこで呼ぶ)

だめだった

でもここで、別のモジュール内でhogeが直接読まれてるとちょっと問題がありました。 直接っていうのはこういうこと:

from mymodule import hoge  # Forever None

このモジュールがひょんなことで読み込まれていると、このモジュール内でのhogeは setup_hogeが呼ばれてもNoneのままです。

setup_hogeが書き換えるのはあくまでmymodule内のhogeなので、別モジュールに読んでいると そっちまでは反映されないんですね。当たり前っちゃそうか。

解決

というわけで間接的に使います:

import module

module.hoge

もしくは取得用の関数を用意する:

# In mymodule.py

hoge = None

def get_hoge():
    return hoge

def setup_hoge():
    ...

これでうまくいきそうです

すぺしゃるさんくす

nakanurayさんとpodhmoさんが教えてくれました

podhmoさんが書いてくれたgistがわかりやすい

ありがとうございます

追記

zope.proxy というのを使うと もっと綺麗/安全に書けるようです

すごい。これならhogeをうっかり直接使っても問題ないですね。 aodagさんが教えてくれました。あzさzs