最近困ったこととか、気付いたことのメモ

久しぶりに django をいじってるせいか、ちょくちょく詰まる。それも、「あれ、前にもここで詰まったような・・・」っていうのが多い。解決できたかどうかも覚えてない。

これはいささかDRY原則の侵犯であると言わざるを得ないので、思いつくままにメモしておく。

モデル定義で文字列の扱いが統一されてない?

validate に失敗して初めて気付いた。unicodeブランチがマージされたので、__unicode__メソッドで unicode を返すように気を付けてたんだけど、あるとき UnicodeDecodeError が発生した。原因は、フィールド定義で verbose_name に unicode を使ってなかったから。
気付くのに手間取ったので、モデル内を全部 unicode にしてみた。今度は list_display でエラーが発生する。こいつは str じゃないとダメみたい。ちょっと分かりにくいなあ。

validate時にDBをチェックしたいけど・・・

django の管理サイトはステキすぎなので、全力でこれを利用したいわけです。でも、ちょっと複雑な validate をやるとすぐ困る。例えば、DB上にレコードが1個しか存在しないモデルを定義したら、2個目を生成するのは阻止したい。モデルのフィールドに validator_list を定義するのはなんか違う気がする。じゃあ save メソッドをオーバーライドして、ValidationError を投げればいいだろう、と毎回考える。ところがこの方法だと、 Error がキャッチされずに Traceback が表示される。レコードの追加は阻止できてるのでOKなんだけど、うまい方法が思いつかない。

カスタム validator と edit_inline は相性が悪い?

ちょっと上のと関係あり。たとえばこんなモデルがあったとして、

class Parent(models.Model):
    # フィールドを定義

class Child(models.Model):
    parent = models.ForeignKey(Parent, edit_inline=models.STACKED)
    other = models.CharField('dummy', validator_list=[custom_validator])

このとき管理サイトで Parent を編集すると、Childもいくつか編集できる。その Child を validate しようとして困った。カスタム validator に渡されるパラメータ、field_data はまあいいとして、all_data は Parent のデータ+Childすべてのデータが入った辞書だ。自分が対象とすべきデータがさっぱり分からないので、validate しようがない。edit_inline 使うなってことか。

テンプレートフォルダは各アプリの直下に置いた方が楽

昔はプロジェクトフォルダの下に templates フォルダを作って、その下に各アプリの名前を持つテンプレート置場を用意してた。この方法だと settings.py にその場所を指定しないといけない。
それに対して、各アプリの下に templates フォルダを作成しておくと、何もしていしなくても探しに行ってくれる。ルースカップリングの点からもこちらの方が全然便利だ。

django のテンプレートは ajax と相性がいい

ajax でページの一部分を変更する、とかがすごい楽。たとえば hoge.html がこんなだった場合、

{% extends "base.html" %}
{% block contents %}
    前半
    {% include "hoge_body.html" %}
    後半
{% endblock %}

ビューではこう書けばいい。

def view(request):
    if 'ajax' in request.GET:
        return render_to_response('hoge_body.html')
    else:
        return render_to_response('hoge.html')

JSONで返したければ、HttpResponse を使えばいい。Javaとか.NETだとこんなに簡単じゃないんだろうな・・・

開発中は管理者ユーザを Fixture に入れておくと楽

頻繁にモデルを修正してると、管理者ユーザの作成が面倒臭い。大した手間ではないんだけど、メールアドレスとかちゃんと入れないとダメなので困る。

なので管理者ユーザを作成した状態で、データをダンプしておく。

python manage.py dumpdata --format=xml --indent=2 > initial_data.xml

不要なデータを削除したら、initial_data.xml をプロジェクトルートか、各アプリの Fixtures フォルダに置いておく。あとは syncdb したときに、管理者ユーザの作成をスキップすればいい。