7月 29

以前のエントリーで集計クエリを利用する方法を説明しましたが、それだとDatetimeのフィールドを「年月」ごとに、っていう集計はできませんでした。購買履歴データを月別に件数集計したいときなんかは非常に困るんですよね。ので、それを解決する方法です。

select_column = {“d_column”:  ”DATE_FORMAT(pub_date, ‘%%Y%%m’)”}
_list = PurchaseRecord.objects.extra(select=select_column)
_list = _list.values(“d_column”).annotate(cnt=Count(‘id’))

上記はMySQLを利用しているケースの書き方です。

あ、横長になると見難いから2行に分けただけで、1行で大丈夫ですからね。

「ORマッパー使ってるのにデータベースに依存ってなによ」

な感じではありますが、extraを使っている部分は直接クエリが流れるみたいですね。
つまり、「DATE_FORMAT(pub_date, ‘%%Y%%m’)」の部分は

select *,DATE_FORMAT(pub_date, ‘%Y%m’) as d_column
from app_purchaserecord

といった風に、追加されるのです。で、追加されたカラムを使って集計、という流れですね。うっかりミスりやすいのが「%」を二つにする点でしょうか。

あと、データベースを変えたら「select_column~」の部分に修正が必要です。使用するデータベースに依存した書き方になります。ここは要注意ですね。

Tagged with:
7月 28

例えば組織図なんかのmodelを構築する際に、「属する部門」を表現するには再帰的なリレーションを使うことになると思います。「部門が属する部門」ですね。

class Div(models.Model):

name = models.CharField(max_length=100)

upper = models.ForeignKey(Div)

だと、syncdbの時に「Divなんてありません」と怒られてしまいます。そりゃそうだ。
ので、

class Div(models.Model):

name = models.CharField(max_length=100)

upper = models.ForeignKey(’self’)

と書きます。

Python2.5、Django1.1.1でのお話でした。

Tagged with:
7月 27

DjangoでMySQLを利用する場合、初期状態だとMyISAMでテーブルが作成されます。まぁ後からalterすればよい話ではあるのですが、なんかそれだと違うかなぁと。

一昔前はInnoDBはMyISAMほどパフォーマンスが優れず、更新系のテーブルと参照系のテーブルでストレージエンジンを使い分けたものですが、今はストレージエンジンによるパフォーマンスの差も少ないため、行レベルロックができるInnoDBを積極的に採用するケースが増えてるみたいですね。まぁ数千万行をレコードから数ミリ秒でレスポンスを返さないといけないケースとかではどうなるのかわかりませんが。

DATABASE_OPTIONS = {
“init_command”: “SET storage_engine=INNODB”,
}

settings.pyに上記を記載するだけでsyncdbするときにInnoDBでテーブル作成してくれます。が、この記述はテーブル作成が終わって運用にはいったら削除するように、とのことです。

MySQLとの接続が確立された後にわざわざストレージエンジンを指定するコマンドを送っているっぽいので、普段は無駄な処理が発生しちゃうっていうことなんですかね。

Tagged with:
5月 19

Djangoでテンプレートを出力するとき、あわせてcookieの書き込みもしたいケースがあります。よくあるサンプルだと

return render_to_response(‘index.html’)

っていう書き方をしているのですが、「コレ、cookieの書き出しどうすんのよ」って悩んでしまいました。その結果、

def  index(request):
_max_age = 45*24*60*60
_expires = datetime.datetime.strftime(datetime.datetime.utcnow() + datetime.timedelta(seconds=_max_age), “%a, %d-%b-%Y %H:%M:%S GMT”)
_response = render_to_response(‘index.html’)
_response.set_cookie(‘hoge’, value=’hogehoge’, max_age=_max_age, expires=_expires, path=’/')
return _response

こんな書き方をしたらできているようでした。上記の例だと、現在時刻から45日間有効なcookieを書き出しています。

単純なことなんですが、意外と躓いてしまった。。。

Python2.5、Django1.1.1です。

そういえばDjangoの1.2がリリースされてますね。検証したいな。

Tagged with:
5月 11

前回のエントリが結局フレームワークの話になってしまったため、新しいエントリを書きました。

同じような処理をさせた場合、どの言語が一番早いのか。非常に気になるところでありますが、試したことがありませんでした。今回試してみたところ、意外な結果が出たのです。

下の方に書いたそれぞれのプログラムを実行した結果の、プログラム内部で計測したミリ秒を比較してます。

PHP Ruby Python
2.80秒 0.36秒 0.93秒

3回計測した平均です。同じ処理をさせるプログラムを書いたつもりですが、本当にフェアなものになっているのか正直自信がありません。そもそもPHPはWebアプリを主な目的としているとのことなので、こういう処理は得意としていないのかもしれない。

また、それぞれのプログラムのループ内2行目、文字列連結の部分をコメントアウトして実行してみると、これまた意外な結果が出ました。

PHP Ruby Python
0.07秒 0.06秒 0.39秒

PHPは文字列連結が苦手なんだろうか。暗黙的な型変換にコストがかかるのだろうか、等々考えてしまいます。それとも秒を求める部分がネックなんですかね。その辺は今後追っていきます。

ただ、これまでPythonの方がRubyより早い、と思っていたために自分の無知さに猛烈に恥ずかしい思いをしています。

実際にMySQLと連携するバッチを書いたときにはRubyの方が遅かったり、Railsアプリがもっさりだったり、「速い」という印象がまったくありませんでした。が、それはある特定の面しかみていない上での思い込みだったのかもしれません。

これはRailsが遅いのか、もしくはMySQL/Rubyが遅いのか。当時の書き方がマズかったのか。今後、いろんなケースでこういった比較をしてみようかと。

今回の検証がすべてではないし、これが答えだとも思っていません。また、そういう意図を含んだエントリではありません。今回の検証だって、特定の面しか見ていません。が、あまりに意外な結果だったため、自戒の念を含めてブログに書きました。

「こう書くともっとフェアだよ」「こういうテストの方がいいんじゃない」等、アドバイスいただけるとうれしいです。

フレームワークまで含めた検証した方が現実的なのだろうか。。。


PHP

#!/usr/bin/php
<?
function microtime_float()
{

list($usec, $sec) = explode(” “, microtime());
return ((float)$usec + (float)$sec);

}
$_start = microtime_float();
$_sec = date(’s’);

for($i=1;$i<100000;$i++)
{

$_val = (mt_rand(0, 100) + $i) / $i;
$_str = $_val.date(’s’);

}

echo microtime_float() – $_start;
?>

Ruby

#! /usr/local/bin/ruby

i=1
_start = Time.now

99999.times do

_val = rand(100) / i
_str = _val.to_s + Time.now.sec.to_s
i += 1

end

p (Time.now – _start).to_f

Python

#!/usr/bin/python
# -*- coding: utf-8 -*-
import datetime
import random

_start = datetime.datetime.now()

for i in range(1, 100000):

_val = random.randint(0, 100) / i
_str = str(_val) + str(datetime.datetime.now().second)

print datetime.datetime.now() – _start


検証環境

CPU:Xeon 1.86GHz
メモリ:2GB
OS: CentOS5.4 32bit
PHP:5.2.11
Ruby:1.8.7
Python:2.5.2

Tagged with:
5月 07

バーコードリーダーではなく、バーコードの画像を作成する方法です。EANコード(JANコード)を作成してみます。

必要なライブラリはhuBarcode。現時点でのバージョンは0.57です。easy_installでもインストールできます。

実はこのhuBarcodeにちょっと問題があって、インストールしたままでは利用できませんでした。

  1. site-packages/hubarcode-0.57-py2.5.egg/ean13/__init__.pyと
    site-packages/hubarcode-0.57-py2.5.egg/ean13/renderer.pyの
    「from functools import reduce」をコメントアウト。
  2. fontsフォルダ(WindowsのFontフォルダではなく、huBarcodeについているもの)site-packagesの下に配置。easy_installの場合は不明だが、ソースからのインストールの場合は手動で配置する必要があった。

「from functools import reduce」はPython3からの記述方法なのかな?Python2.5の環境では動きませんでした。

ここまでが前準備。やっとコーディングに入れます。

from ean13 import EAN13Encoder

_barcode = EAN13Encoder(‘123456789012′)
_barcode.save(“sample.png”)

コーディングは簡単。これだけでバーコードのpng画像が作成されます。EANは13桁ですが、最後の一桁はチェックサムなので、指定できるのは12桁までです。

どっちかっていうと二次元コードの方がニーズがあるだろうから、そっちも調査してみます。

Tagged with:
4月 28

Windows環境とLinux(CentOS5.4)環境とで異なったのでメモ。

import locale

locale.setlocale(locale.LC_ALL,’ja’)
print locale.format(‘%d’, 123456789, True)

Windows環境ならこれでOKですが、Linux(CentOS5.4)環境なら、以下になります。

import locale

locale.setlocale(locale.LC_ALL,’ja_JP.UTF-8′)
print locale.format(‘%d’, 123456789, True)

環境の文字コードにも依存するんだと思います。環境のlocaleに関する情報は

locale.setlocale(locale.LC_ALL,”)

で取得できます。

Python2.5です。

Tagged with:
4月 27

ハセテツは複数の言語を状況に応じて使い分けてきましたが、最近のWeb系開発はPython(+Django)がメインになってきています。

ちょっと前までRuby(+Rails)だったのですが、いろいろと考えるところもあり、乗り換えました。その乗り換えた理由をまとめてみようと思います。

まとめてみたら「やっぱりRailsじゃね?」となるかもしれません。w

Ruby(+Rails)

  • Rails便利すぎる。
  • コントローラとモデルが別々のファイルになってくれるのはソースが追いやすい。
  • Railsを通さない画像やCSSはpublicフォルダに置けばよいのはわかりやすい。
  • urlディスパッチャーがいまいち使いにくい。(知らないだけかも)
  • APサーバはmongrel一択?
  • VirtualHost使おうとするとApache+Passenger(mod_rails)だが、これが重い。(チューニングで速くなるのかも)
  • というか、Railsがそもそも重い。
  • ちゅーか、Rubyが重い、遅い。
  • PassengerはWindowsじゃ動かない。
  • mongrelもPassengerより激速軽快かというと、そうでもない。
  • gem便利すぎ。
  • ワンライナで書く人が多くて、Perlとおなじ匂いがする。

ハセテツが使っていたRubyは1.8で、速くなったといわれる1.9には触れていないのでもしかすると古いのかもしれません。でも、Railsって1.9には対応してないですよね?(本日現在)

Python(+Django)

  • Django便利すぎる。
  • 日本語の書籍、情報が少なすぎる。(ハマるとキツい)
  • modelが一枚のファイルなので、大量のmodelがあると可読性が激しくダウン。
  • viewファイルをフォルダで分けたくても、アプリケーションフォルダ直下以外にviewファイル置くなら「sys.path.append」しないといけない。(違う?)
  • urlディスパッチャーのカスタマイズが超便利。
  • mod_pythonが使えるので、Windows環境だろうがLinux環境だろうが気にせずVirtualHostが使える。
  • 速い。
  • 日本語大変。Shift_JIS怖い。
  • easy_installでパッケージのインストールは楽だが、管理が悪夢。

メリットとデメリットが入り乱れました。見難くてすいません。

結局フルスタックのフレームワークということで、DjangoとRailsに関しては一長一短だと思います。個人的にはRailsの方が良くできてたかなぁと。

最終的に、「RubyonRailsは重い」というオチになってしまうのです。Rubyも、Railsも、です。ただ、これはRuby1.9が実は劇的に速くなっていて、1.9に対応したRailsがリリースされたらすべて解決されるのかもしれません。

それでも、いまのところPythonの軽快さ、シンプルさに満足しています。あと、GAEでPythonが動くのもいいですよね。

「Googleが導入した言語」というのがハセテツ的に琴線に触れたのかもしれません。

ミーハーですいません。w

Tagged with:
4月 22

携帯メールでのブログエントリ投稿だったり、ユーザ登録だったり、メールのパイプ処理って結構重要だと思います。パイプさせなくてもcronで定期的にPOPすればいい話ですが、それだとユーザからのリクエストに対してシームレスに反応できないですよね。それはなんかイヤなんです。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys, os, email

_mail = email.message_from_file(sys.stdin)

for item in _mail.walk():

if  item.get_content_maintype()==’text’:

_file = open(‘/path/to/save/log.txt’, ‘a’)
_file.write(_mail['Subject']+’\r\n’)
_file.write(item.get_payload(decode=True)+’\r\n’)  #body
_file.close()

elif  item.get_content_maintype()==’image’:

_filename = item.get_filename()

_attache = open(‘/path/to/save/’+_filename, ‘wb’)  #添付ファイルを保存
_attache.write(item.get_payload(decode=True))
_attache.close()

Python2.5です。

標準入力で読み込んで、要素(きちんと理解できてないのですが、boundaryで区切ったものってことだろうか)ごとにイテレートして、content_maintypeがtextなのかimageなのかで処理を分岐しています。ちなみに、content_maintypeはExcelファイルだったら「application」になります。

なお、エンコード処理入れてないのとエラー処理入れてないのです。いつものことなのです。

Tagged with:
4月 21

隠蔽するっていうか、viewにごりごり書くのではなくてModelのメソッドで処理してしまおうという話です。このエントリの応用ですね。

import hashlib

class Member(models.Model):
    name = models.CharField(max_length=32)
    passwd = models.CharField(max_length=256)
    def save(self, force_insert=False, force_update=False):
        self.passwd = hashlib.md5(self.passwd).hexdigest()
        super(Member, self).save(force_insert, force_insert)
Modelのsave()メソッドをオーバーライドしています。これで、登録フォームなどからPOSTされたデータをそのままsave()してもデータベース上には暗号化された状態で保存されます。
adminサイトで作成したユーザ情報なんかのパスワードとかも、暗号化して保存してくれます。便利便利。
Tagged with:
Get Adobe Flash playerPlugin by wpburn.com wordpress themes
preload preload preload