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:
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月 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:
4月 20

コンボボックスの<option>~</option>の値は動的に指定したいものです。が、Djangoでどうしたらよいものか、数時間悩みました。

これが意外と簡単で、こんなことで数時間悩んだ自分が情けなく、それでも発見した自分をほめてやりたく。w

class Form_hoge(forms.Form):
    month = forms.ChoiceField()
_form = Form_hoge()
_form.fields['month'].choices = [(1,1), (2,2), (3,3)]
フォームを呼んだ後に指定するだけ。
なんですぐ気づかなかったんだろ。。。
Django1.1.1、Python2.5で動作検証。
Tagged with:
4月 20

Djangoのモデルで集計クエリというと、1.0以降でcount()が使えますが、1.1になってさらに多機能になっていました。

from django.db.models import Sum

_result = Detail.objects.all().values(‘category’).annotate(price=Sum(‘price’))
for item in _result:

    print item

Detailというモデルがあって、それをcategoryというフィールドでグループ化し、priceというフィールドのsum(合計)を求めています。

values(~)は必須ではありません。グループ化しないと全体のsumですね。

annotate(得られる結果の名前=Sum(集計対象フィールド))

です。サンプルの「price」をsum_priceにしても結果は得られます。

また、annotateで利用できるのはsumだけでなく、Avg、Max、Min、Countも使用できます。サンプルコードだとSumしかインポートしていませんが、「*」でまとめてインポートするか、「Avg, Max, Min, Sum, Count」をそれぞれインポートしてあげれば使用できます。

ちなみに、サンプルコードで得られるitemは、Detailモデルのインスタンスではありません。辞書です。最初ここに気づかず、「?」となっていました。w

Tagged with:
4月 06

Djangoのフォームでclassを指定する方法です。Widgetクラスを使うのですが、情報が少ないような気がします。探し方ヘタ?

class Form_login(forms.Form):
    mailadd = forms.EmailField(max_length=32,widget=forms.TextInput(attrs={‘class’:'form_entry’}))
    passwd = forms.CharField(min_length=6, max_length=12,widget=forms.PasswordInput(render_value=False))

これで出力されるフォームには「class=”form_entry”」が追加されます。

パスワード側もWidgetクラスを使用していますが、Widgetクラスを活用するとDjangoのフォームってものすごく便利に活用できるような気がします。

Django 1.1.1、Python2.5で検証しました。

Tagged with:
3月 26

PHPでいうところの$_SERVERですね。

request.META.get(‘HTTP_HOST’)

ホスト名はこんな感じです。リファとかユーザーエージェント(ブラウザ)もここで。モバイルの場合端末識別番号も取得できますね。

Tagged with:
Get Adobe Flash playerPlugin by wpburn.com wordpress themes
preload preload preload