Django
Jul 13, 2009
手元でdjangoをwsgiで動かす
手元のPCでまともにDNSを動かしているわけではないのでちょっと工夫。
apacheを工夫というよりDNS(unbound)の工夫だな。
unbound.confに以下を追加。
local-zone: "local." static
local-data: "django.local. IN A 127.0.0.1"
とやりまして、django.localに対してVirtualHostを設定するという流れ。
Apacheのほうはwsgiを設定するところの肝心なところだけ再掲。
Alias /media "/usr/share/pyshared/django/contrib/admin/media"
<Directory "/usr/share/pyshared/django/contrib/admin/media">
Order allow,deny
Options Indexes
Allow from all
IndexOptions FancyIndexing
</Directory>
WSGIScriptAlias / "/home/takaki/src/django/myproject/apache/django_app.wsgi"
<Directory "/home/takaki/src/django/myproject/apache/django_app.wsgi">
Allow from all
</Directory>
May 07, 2009
modelformset_factoryのこと
modelformset_factoryを作ってフォームの一括処理をしようとしたらどうも挙動がおかしい。
ModelFormSetを作って新規のフォームを初期データ付きで作成しようとした。しかし新規にデータを挿入しているつもりなのに既存のデータが上書きされる。なぜだなぜだと考えていたがそもそもそういう挙動だった。
TheModelFormSet = modelformset_factory(TheModel)
print TheModelFormSet(inital=init_data)
だいたいこのような記述になるがほっておくとフォームの雛形をTheModel.objects.all() 相当から作ることになる。そこから初期値が、特にidが作成されてしまう。idがフォームのパラメータに含まれるということはinsertではなくてupdateの挙動になる。まいった。
完全にデータの入ってないフォームを作成しようと思ったらできる。例えばhttp://code.djangoproject.com/ticket/9538にあるようにすればできる。ただ、これにinitialを引数で与えるとエラーになる。initialはquerysetで作成したModelのインスタンスに対して適用しようとするので、当然数が合わずにエラー。initialのパラメータに {'id':None}を渡してやれば id が空のフォームはできるが必要のないquerysetを内部で実行することになる。それも気持が悪い。
自分でTheModelFormを作成してから TheModelFormSet を作成すればもちろん問題ないがめんどくさい。はてさて、簡単な方法がないものか。
Feb 01, 2009
zptからgenshiに移行
個人的に作っているdjangoのソフトのテンプレートをzptからgenshiに移行した。
djangoでのzptのサポート自体がどうなるやらあやしいところもあるしzope自体にpythonのサポートがどうしても遅れているのでgenshiに切り替える。手法は似ているので基本的にはキーワード置き換えを順番にやっていく感じ。
- py:contentとか使わず${}記法で書いてしまうのも良し悪しか。
- タグに入ったデータをescapeさせないときには <?python from genshi import HTML ?> ${HTML(data)} という書き方をする。
- pythonのコードを直接書けるのもよしあしか。
generic viewでgenshiを使う
Djangoでgeneric view を使っているときにgenshiを使うにはオプション引数を渡せばよい。
template loaderをGenshiのloaderに変更させる。url.pyに以下のような記述となる。
url(r'^myapp/(?P<object_id>\d+)/view/$', object_detail,
dict(some_dict,template_loader=django_genshi.loader),
でも駄目みたいだ。generic_viewの中身がdjangoのtemplateでしか動かないようになったいるようだ。なんか変けど、
'MarkupTemplate' object has no attribute 'render'
とのエラーが出る。もうちょっと調査。
Dec 10, 2008
django + genshi 続き
いくつかメモ
- djangoの便利なテンプレートがそのまま使えるわけではないのでちょっと面倒なこともある。
- ifchanged は <?python > を使ってコードを書く必要があった。あまりいいとは思えないが…。
- url はreverseを呼ぶだけだからまだ楽か
<?python
last_seen = None
?>
<py:for each="object in objects">
<py:if test="last_seen} != object.key">
<tr><td>${object.get_value()}</td></tr>
</py:if>
<?python
last_seen = object.workflow
?>
...
</py:for>
urlの例
<?python
from django.core.urlresolvers import reverse
?>
<a href="${reverse('my-view',args=[2005])}">link</a>
Dec 09, 2008
django_genshiをちょっとする
genshiでdjangoをやりたかったので。
やっぱりテンプレートはvalidなXMLでないと気分がよくない。ZPTを使っていたが全然アップデートされてないのとzopeがpython 2.4で止まっているので Genshi を使ってみることにする。使い方は簡単。
サンプルにあるとおり以下のようにするだけ。
from django_genshi import render_to_response
def index(request):
return render_to_response('myapp/index.html', {'var_name' : 1234})
となる。ただテンプレートのローダーが問題。READMEにも説明があるがサンプルをちょっと書いてくれれば親切だったのに。
settins.pyに GENSHI_TEMPLATE_LOADER を書けと書いてあるが…次のようにする。
GENSHI_TEMPLATE_LOADERS = (
'django_genshi.loaders.app_directories.load_template',
'django_genshi.loaders.filesystem.load_template',
)
django_genshiの持っているテンプレートローダーを使用する。そこがはまったポイントでした。
Dec 06, 2008
djangoのlogin処理
djangoのユーザー認証を使ったlogin・logoutの処理のメモ
公式ドキュメントのAuthenticationを参考。
myproject/myapp/views.py:
from django.contrib.auth.decorators import login_required
#
@login_required
def view_func(...):
##
myproject/urls.py:
(r'^accounts/login/$', 'django.contrib.auth.views.login'),
(r'^account/logout/$', 'django.contrib.auth.views.logout_then_login',
{'login_url': '/myappurl/'}),
てな具合。logoutすると自動的にログイン画面に戻るようにする。
Jul 27, 2008
Django 1.0alpha の admin
Django 1.0 alpha で newforms-adminがmergeされた。
admin画面が大幅に変わってしまった。Tutorial のpart 2を参考に…。claa Adminを宣言するのではなく別にAdmin用のクラスを定義する感じになっているな。全部そういう修正となるわけですか。
Apr 29, 2008
Queryset-refactor branch has been merged into trunk
djangoのQueryset-rafactorブランチがtrunkにマージされた。
Mar 15, 2008
modelのunicode表現
Djangoのmodelのunicode表現ではまったことのメモ
- 個々のフィールドはunicodeで自動的に来る。
- 以前にmodelをstr()で変換していたところはunicode()にしないとおかしくなる。
Mar 08, 2008
new-formsの仕様変更
djangoをsvn 6903 から 7189ベースに移行しようとしたがnewforms周辺で苦労してます。
Feb 25, 2008
modwsgiとMD5の続き
PythonのMD5がmhash2のMD5とでシンボル名が衝突するのでApacheがまともに扱えなくなる件が解決していた。
440272 でPython2.4のバージョンアップで解決されていた。djangoでログイン処理等ができちんとできることも確認。
Jan 18, 2008
djangoとunicodeのメモ
CharFieldとかTextFieldを読み込むとUnicode型で帰ってくる。
Dec 10, 2007
django svn (r6903)
djangoをtrunkの最新版に移行。
unicodeまわりでエラーが多発。__str__を__unicode__にしたら問題はなくなった。他にもあるんだろうけど、とりあえずは問題がない。あとurls.pyの書き方が厳しくなって存在しないメソッドを書いておくとエラーになる。
MLではバージョンナンバーの付け方で揉めているようだけど、なんでもいいから次のリリースを出してくれって。
templatetagをつくってみる
自分でdjangoのtemplatetagsを作ってみた。
数字の3桁区切りをやりたかったのでlocale.formatを使うフィルターを書いてみた。
myproject/app/templatetags に __init__.pyとlocaleformat.pyを配置。__init__.pyは空ファイル。
from django import template
import locale
register = template.Library()
@register.filter
def localeformat(num):
locale.setlocale(locale.LC_NUMERIC,'ja_JP.utf-8')
return locale.format("%d", num, True)
ロケールが決め打ちなのは気にしないように。ドキュメント通りです。注意しなければならないのはINSTALLED_APPSに書いてないとtemplatetagsの下を見に行きません。
ソースを読んだところ django.templatetags の中で検索パスを書き直しているのがわかった。つまりですねー、django.templatetagsというパッケージ名があったら実ファイルパス(/usr/lib/python/django/template)に内部で対応させているわけですが、それに /path/to/myproject/app/templatetags のファイルパスも見てねと追加しているんだなと。はは、そういうふうにloadを隠蔽しているわけですか。
Oct 31, 2007
modwsgiとMD5
djangoをwsgiで動かそうとすると認証ができない。
なぜかクッキーが有効になってないと表示される。多分セッション回りでおかしいのだという検討がつくが…。djangoのrunserverからは大丈夫でapacheからは駄目という謎挙動。クッキーを見るとsessionidの先頭8文字が0にあるという妙な具合になる。
32bitと64bitとの違いなのかとも悩む。Session.objects.get_new_session_key()を出力させるとやはりおかしい。md5の出力もやはり先頭が0になっている。しかもmd5.new('1')もmd5.new('2')も同じ結果になるがリロードする度に値が変わる。sessionが維持できなかったのはmd5の挙動がおかしいのが原因ということまでは突き止めたが、なぜおかしいのかがわからなかった。
で、探してみると原因が判明。mhash2どシンボル名が衝突していたによるものだった。削除してみたら挙動が正常になった。PHP回りで使用しているんですよねえ。python-2.5からは実装が変更になったから大丈夫らしいが…。
- http://code.google.com/p/modwsgi/wiki/ApplicationIssues (Python MD5 Hash Module Conflict)
Oct 09, 2007
djangoのView・お悩み中
djangoのModelとViewの関係について悩む。
- あるモデルを書く
- 表示するときにテンプレートでModelのデータから演算すると見通しが悪くなる場合がある。
- データの操作をしたくても、そもそもdjangoのtemplateの能力は貧弱(ZPTに比べて)
- なのでview.pyに書く。
- とは言え共通する操作が出てくる。
- DRYの原則によりまとめたほうがいい。
- でもまとめたメソッドはviewに書くとtemplateから呼び出せない
- TheModelのインスタンスメソッドとしてget_hoge(self)・get_calculate_bar(self)が増殖
- いいのかこれで。
- この議論は合っているのかな。
- TheModelに対応したTheModelViewというクラスを作ればいいのか?
- カスタムタグの話に行けばいいのか?
- お悩み中。
Oct 04, 2007
generic_view ハマリ例
Djangoのgeneric viewでdjango.views.generic.date_based.archive_monthを使って悩む。
URL_PREFIX/(P?<year>\d+)/(P?<month>\d+)/$ とかやっていたがなぜか駄目で。ドキュメントを読むと month_format でformatを設定しないと%b(JanとかFebとか)になるとのこと。%mに設定して動作したが、locale依存で優しくないと思う。
それと next_month が二日(9月だと10/2)に設定されるのはなんででしょう。10/1に9月のnext_monthがfuture扱いってのはおかしいでしょ。ドキュメントにはfirst day of the next monthと書いてあるのになあ…。
Sep 27, 2007
Django + modwsgi
DjangoをApacheのmodwsgiで動かす。
必要なパッケージ
- libapache2-mod-wsgi
/home/takaki/devel/django_app で開発しているとする。
apacheの設定ファイルのように記述。/etc/apache2/site-availableなどを利用する。
Alias /media/ "/usr/share/python-support/python-django/django/contrib/admin/media/"
<Directory "/usr/share/python-support/python-django/django/contrib/admin/media">
Order allow,deny
Options Indexes
Allow from all
IndexOptions FancyIndexing
</Directory>
WSGIScriptAlias / "/home/takaki/devel/django_app/apache/django_app.wsgi"
<Directory "/home/takaki/devel/django_app/apache/django_app.wsgi">
Allow from all
</Directory>
/home/takaki/devel/django_app/apache/django_app.wsgiを以下のように書く。
import os, sys
#Calculate the path based on the location of the WSGI script.
apache_configuration= os.path.dirname(__file__)
project = os.path.dirname(apache_configuration)
workspace = os.path.dirname(project)
sys.path.append(workspace)
os.environ['DJANGO_SETTINGS_MODULE'] = 'django_app.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
これだけで動く。意外と簡単だった。develとproductionで分けたいとかは参考文献を見て下さい。
Sep 23, 2007
generic viewのextra_context (2)
間違っていた話。
extra_context に QuerySet渡すと静的に解決されて困ったな、という話ですがwww.lingr.com/room/django-ja/archives/2007/09/19 で指摘されているようにlambdaで囲うのが正解でした。折角なのでソースを読む。
- あたり前の話として dictionary は静的に値が決まる。つまり値で関数を呼べばその結果が入る。
- じゃあなんでlambdaならいいんだよという話は django/views/generic/list_datail.py で extra_context の値を RequestContextに渡すときに callable な物はその場で呼び出した値を渡すから。
- 以上が結論。あ、でも関数を渡せたとしても関数自体は静的に決まるから…、これはまた考えよう。
ドキュメントを斜め読みしないでもうちょっとソースを読もう…。

