Home > Django Archive

Django Archive

[django]デフォルトマネジャのget_query_setをいじったらsaveできなくなった

あるmodelに削除フラグを追加したので、かならずそのフラグを参照するようにget_query_setをオーバーライドしたマネジャを用意し、それを該当modelのデフォルトマネジャに設定した。

マネジャ — Django v1.0 documentation

とはいえ、削除フラグのたっている(削除済み)のデータも扱いたいときがあったんで、別のマネジャを使って削除済みデータを取得してsaveしたら、PKの重複エラーが出てしまった。
どうやらUpdateではなくInsertしようとしたみたい。

ソースをちらっと見たところ、デフォルトのマネジャで検索してInsertするかUpdateするか判断しているっぽい。

カスタムのマネジャオブジェクトを使う場合、 Django がモデル内に最初に見つけたマネジャ (モデルに定義した順番で最初のマネジャ) は特別扱いされるということに注意してください。 Django はクラス内で最初に見つけたマネジャを「デフォルトの」マネジャにし、このデフォルトマネジャを (admin アプリケーション以外でも) あちこちでモデルのマネジャとして使います。ですから、 get_query_set() のオーバライドによって、扱いたいオブジェクトを取り出せなくなるような羽目に陥らないように、デフォルトマネジャの選択には細心の注意を払ってください。

マニュアルには、確かに注意しろと書いてあるけど、まさかsaveできなくなるとは。
saveのデフォルト動作としては正しい気がするんだけど、なんか回避策はないのかなぁ?
force_update=Trueとしても、丁寧に行の存在チェックをしているみたい。

その行は絶対に扱わないということでも無い限り、デフォルトマネジャのget_query_setに細工するのは危険っぽいですね。

[django]さくらインターネットでPILがエラー

嫁のブログ(NUI)で、ほかの人が作った作品をアップロードする機能をdjangoで実装していたんだけど、ユーザーからの報告、つまりコメントでうまく動かないという報告が。

で、見てみたらPILのthumbnailメソッドでエラーが発生している。
djangoは「The _imaging C module is not installed」っていっている。

サーバーに入ってpython立ち上げて確かめてみる。

>>> import PIL
>>>

これは大丈夫。

>>> import _imaging
Traceback (most recent call last):
File ““, line 1, in ?
ImportError: Shared object “libz.so.2″ not found, required by “_imaging.so”
>>>

うーん。サーバーのバージョンアップでもしたのか。
/usr/libの下を見ると、libz.soはlibz.so.3へのシンボリックリンクになっている。

こりゃPIL入れ直しか。

http://www.pythonware.com/products/pil/
ここから落としてきてインストール。
ライブラリは、$HOME/local/lib/python/に入っているので、–homeでディレクトリを指定。

$ wget http://effbot.org/downloads/Imaging-1.1.6.tar.gz
$ tar xvzf Imaging-1.1.6.tar.gz
$ cd Imaging-1.1.6
$ python setup.py build
$ python setup.py install –home=$HOME/local

復旧。
よかったよかった。

[django]DateTimeFieldのdefault

DateTimeFieldのdefaultに、
xxx = models.DateTimeField(default=datetime.datetime.now())
と指定していたら、なんかおかしな値が入る。

具体的には同じ日付のデータがたくさん。すべてのデータが同じ日付な訳ではないけど。
ちなみに、テスト環境ではちゃんとしたデータが入る。

datetime.datetime.now()が評価されるのはプロセスが起動してクラスを読み込んだときっぽいね。
そりゃそんな気がするね。
だからプロセスごとに違う時間だけど、同じ時間がたくさん入るのか。
テスト環境は、1アクセスごとにプロセス再起動の設定になってるから問題ない様子。

auto_now_add=Trueとか使わなきゃいかんかなーと思ったら以下の情報を発見。
モデルフィールドのデフォルト値 - 偏った言語信者の垂れ流し

defaultの値を毎回評価するためには、関数を指定する。

callableかどうかを判断して、適切に関数を呼び出してくれるらしい。
解決。
ありがとうございました。
てことは、defaultは自分で作った関数とかも使えそうだね。

ところで、auto_nowとかauto_now_addとか無くなるって噂を見たことがある気がしてたんだけど、ドキュメントを見る限り残ったのかな?使っても良さげ?

[Django]もう少しでサイトオープン

いや、実際にはもうオープンしてるんだけど、デザインなどまだ調整中。
特にIEがだめなのと、一部のデザインは普通に崩れてるのと、地図がテンポラリーですが、サイトをオープンするのを最優先した。
単純なサイトで、Djangoじゃなくてもいいくらいのサイトなんだけど、URLの処理とモデルだけでも使う価値があるなーと再認識。

まだ調整中ですがこれ。
温泉 | ヨイヤド.jp - 高評価な温泉宿探しはヨイヤド.jp。口コミの評価が高い温泉旅館、人気のホテルや露天風呂付き民宿もすぐに見つかる。

本家のサイトよりも見やすくて探しやすくなってると思います。

[Django]本について

これはいいなー。
なんと言ってもこの網羅感がすばらしい。
オンラインマニュアルよりも突っ込んだ内容もあり、普段Djangoを使っている人でも1冊手元にあるとよいのでは。
完全解説っていう表紙の言葉が誇大表現じゃないところがすごい。
買ってよかった。

というわけで、非常によくまとまってお役立ちな本なのですが、あえて(恐れ多くも)苦言を呈するとしたら・・・

  • 初心者に取っ付きやすい内容ではない。
  • 紙面が硬派っぽい印象を与える。オライリー並み?に硬派。もちろんいいことでもあるんだけど。

ようはマニュアルでチュートリアルくらいやってみて、その上で興味をもって深くやってみようという雰囲気の本なのかなーと感じる。
感じるだけで中身は非常に丁寧で分かりやすいんだけどね。
なんでそう思うんだろう?
色がついてないから?
あなたもすぐ作れます、みたいな誇大広告がないから?

それが逆に好感にもつながってるところが難しい。
しばらくこの路線で地道に進んでいくのがバブルにならずにいい気もする。

開発のプロが教える標準Django完全解説―Webアプリケーションフレームワーク (デベロッパー・ツール・シリーズ)
増田 泰 中居 良介 露木 誠 松原 豊
アスキー・メディアワークス
売り上げランキング: 9602

Django!!

即効予約した。

標準Django完全解説 開発のプロが教える
角川グループパブリッシング
売り上げランキング: 6761

1.0ももうすぐだし、GoogleAppEngineもあるし、盛り上がってきてるよね!

変に暗黙の処理をされず黒魔術感がほとんどなく、といっても記述量が多いわけでもない。
設計が綺麗で見通しが良く、作ったアプリケーションも読みやすい。
そんなイメージ。

Django newformsのBooleanFieldで問題

newformでBooleanField関連のバグ(?)にあたった。
使っているのはsvn最新版のDjangoでバックエンドはMySQL5.0。

1.modelでBooloeanFieldを定義する
2.データベースにはtinyint型になる -> 0 or 1が入る
3.ModelFormを使ってフォーム作成
4.as_hiddenで出力 -> valueには0が設定される
5.そのままフォームで受け取ってバリデーション
6..データがTrueになってる!

Djangoのソースを見てみる。

newforms/forms.py 533行目から

PYTHON:
  1. class BooleanField(Field):
  2.     widget = CheckboxInput
  3.  
  4.     def clean(self, value):
  5.         """Returns a Python boolean object."""
  6.         super(BooleanField, self).clean(value)
  7.         # Explicitly check for the string 'False', which is what a hidden field
  8.         # will submit for False. Because bool("True") == True, we don't need to
  9.         # handle that explicitly.
  10.         if value == 'False':
  11.             return False
  12.         return bool(value)

bool(value)で0という「文字列」がTrueとなって返るみたい。
うーん。Falseって文字列だけチェックはまずくない?
"which is what a hidden field will submit for False"って、0か1が入ってるよ!

参考までに、db関連のコードがどうなっているか見てみた。

db/models/fields/__init__.py 445行目付近

PYTHON:
  1. class BooleanField(Field):
  2.     def __init__(self, *args, **kwargs):
  3.         kwargs['blank'] = True
  4.         Field.__init__(self, *args, **kwargs)
  5.  
  6.     def to_python(self, value):
  7.         if value in (True, False): return value
  8.         if value in ('t', 'True', '1'): return True
  9.         if value in ('f', 'False', '0'): return False
  10.         raise validators.ValidationError, _("This value must be either True or False.")

db/backends/utils.py 86行目

PYTHON:
  1. def typecast_boolean(s):
  2.     if s is None: return None
  3.     if not s: return False
  4.     return str(s)[0].lower() == 't'
  5.  
  6. 〜数行省略〜
  7.  
  8. def rev_typecast_boolean(obj, d):
  9.     return obj and '1' or '0'

二つのコードは違うけど、似たような処理をしている。
(typecast_booleanのほうは、文字列の0や1が入るのは想定していない様子。)
こんな感じの実装をnewformsのほうにも入れるべきなんだろうなー。
今回はカスタムフィールドを作る練習として、自分でMyBooleanFieldを定義して回避しといた。

関係ないけど、ModelFormはform_for_modelとかform_for_instanceに比べて自然な感じでいいと思う。

さくらインターネットでDjango、再び

[補足]さくらインターネット、CGIでDjangoを動かすで、mysqlのバージョンが古いので文字コード指定のソースをコメントアウトするというイレギュラーな対応をしていたが、それだけだと問題がありそう。

[Django][本棚開発ログ][さくらインターネット] Django を最新にupdateしたら困ったことになった。
※コメントにも書きましたが、こっちでも紹介しとこうとエントリーにしました。トラバも送っときます。

で、マニュアルを見てみたんだけど、こんなことが書いてあった
データベースのサポート状況 : Django オンラインドキュメント和訳 - MySQLdb

古いバージョンの MySQL と mysql_old バックエンドを使うつもりなら, おそらく 1.2.0 で動作するでしょう.

というわけで、django/db/backends/ の中の、mysql と mysql_old を入れ替えてちょこっとadminを触ってみたけど、どうやら正常に動いている様子。re_guzyさんとは違ってDjangoは0.96のままだけど。
これで上手く行ってくれると良いな。

ちなみにDjangoのマニュアルによると古くないMySQL=推奨されるバージョンは4.1以降らしい。そりゃそうだ。
さくらインターネットさん、なんとかバージョンアップできませんかね?
ユーザーが多いから難しいのは分かるけど。

勉強会行ってみたいけど・・・

勉強会いいなあ
Django勉強会 Disk 4

もう少しこういうので外に出て行って世界を広げたいと思う。
会社に何万円も出してもらっていく研修よりもよっぽど価値がありそうだし。

ただしこういうのは土曜日が多いみたいだけど、毎週空手の稽古なんだよね。
(この日は所属団体の全国大会だけど。)

そのうち上手く時間があったら参加したい。

Safariで文字化けでDjangoのHttpRequestのcharset指定などを見直す

男の小遣い帳で、Ajaxでデータを取得したときにSafariで文字化けしていた。
自宅のサーバーでは動いていたからおかしいなーと思ってたんだけど、レスポンスヘッダのContent-Typeにcharset指定が無かったようだ。

自宅ではhttpd.confに
AddDefaultCharset UTF-8
と書いていたけど、共用サーバーでそんな設定はしないよな。

とりあえずDjangoからAjaxのレスポンスを返すときに
values = simplejson.dumps(data, ensure_ascii=False)
return HttpResponse(values, mimetype="text/plain")

となっていたのを以下に変更。
values = simplejson.dumps(data, ensure_ascii=False)
return HttpResponse(values, mimetype="text/plain; charset=UTF-8")

この対応で大丈夫か確認のため、一応Djangoのソースを見てみた。
HttpRequestクラスでは
def __init__(self, content='', mimetype=None):
from django.conf import settings
self._charset = settings.DEFAULT_CHARSET
if not mimetype:
mimetype = "%s; charset=%s" % (settings.DEFAULT_CONTENT_TYPE, settings.DEFAULT_CHARSET)
if not isinstance(content, basestring) and hasattr(content, '__iter__'):
self._container = content
self._is_string = False
else:
self._container = [content]
self._is_string = True
self.headers = {'Content-Type': mimetype}
self.cookies = SimpleCookie()
self.status_code = 200

となっていて、mimetype指定があるときはそのままContent-Typeに突っ込んでいるので、charset指定も普通のヘッダのように書き足してOKっぽい。
mimetypeにcharsetが入っていなかったら、自動的にDEFAULT_CHARSETを追加してくれれば良いのに。HttpResponseにmimetypeを指定するときは、charsetも入れておいたほうが良さそう。

これでとりあえず動いたんだけど、どうやらSafariはそもそも文字化け問題を含んでいるらしい。
(恥ずかしながら知らなかった。)
古いSafariだとContent-Typeでちゃんとcharset指定してもダメなのかな?

とりあえずJavascriptも直しておこうというわけで、以下を参考に直した。
[ajax] Safari の responseText で UTF-8 コード文字化け回避 Kawa.netブログ(川崎有亮)/ウェブリブログ
最速インターフェース研究会 :: SafariのAjaxの文字化けをクライアント側だけで対応するバッドノウハウ
レスポンスヘッダでcharsetを返さなくても、この対応をすれば動作した。

サーバー側もJavascript側も対応して、とりあえず完了。

Home > Django Archive

Search
Feeds
Meta

Return to page top