情報(django)をログに記録するときにget_FOO_display()が整数値を返すのはなぜですか?
値を制限するための選択肢を使用しているモデルフィールドがあります。これは正常に機能し、get_FOO_display()メソッドが人間が読める形式ではなく基になる整数値を返す場合を除いて、アプリ内のあらゆる場所で機能します。
これはモデル定義です(要約):
THING_ROLE_MONSTER = 0
THING_ROLE_MUMMY = 1
ROLE_CHOICES = (
(THING_ROLE_MONSTER, u'Monster'),
(THING_ROLE_MUMMY, u'Mummy'),
)
# definition of property within model
class Thing(models.Model):
...
role = models.IntegerField(
'Role',
default=0,
choices=ROLE_CHOICES
)
これを(django)インタラクティブシェル内で実行すると、期待どおりに動作します。
>>> from frankenstein.core.models import Thing
>>> thing = Thing()
>>> thing.role = 0
>>> thing.get_role_display()
u'Monster'
ただし、文字列のフォーマット/ロギングシナリオ内でまったく同じ構成を使用すると、問題が発生します。
logger.info('New thing: <b>%s</b>', thing.get_role_display())
戻り値:
New thing: <b>0</b>
ヘルプ!
[更新1]
インタラクティブシェル内でロギングを実行すると、正しい出力が得られます。
>>> from frankenstein.core.models import Thing
>>> import logging
>>> thing = Thing()
>>> thing.role = 0
>>> logging.info('hello %s', b.get_role_display())
INFO hello Monster
[更新2]Djangoの内部
以下の@joao-oliveiraからの回答に続いて、私は内部を掘り下げ、次のことを明らかにしました。
の基になる_get_FIELD_displayメソッドはdjango.db.models
次のようになります。
def _get_FIELD_display(self, field):
value = getattr(self, field.attname)
return force_unicode(dict(field.flatchoices).get(value, value), strings_only=True)
コードにブレークポイントを設定してからipdbを実行すると、問題があることがわかります。
ipdb> thing.get_role_display()
u'1'
ipdb> thing._get_FIELD_display(thing._meta.get_field('role'))
u'1'
したがって、修正によって何も変更されていません。次に、_get_FIELD_display
メソッドコードを手動で実行しようとすると、次のようになります。
ipdb> fld = thing._meta.get_field('role')
ipdb> fld.flatchoices
[(0, 'Monster'), (1, 'Mummy')]
ipdb> getattr(thing, fld.attname)
u'1'
ipdb> value = getattr(thing, fld.attname)
ipdb> dict(fld.flatchoices).get(value, value)
u'1'
これは次のように言うのと同じです。
ipdb> {0: 'Monster', 1: 'Mummy'}.get(u'1', u'1')
u'1'
それで。私たちが抱えている問題は、メソッドが文字列値u'1'
を使用して選択肢辞書で対応する説明を検索しているが、辞書のキーは整数であり、文字列ではないということです。したがって、一致するものは得られませんが、代わりに、既存の値(文字列)に設定されているデフォルト値が得られます。
キャストを手動でintに強制すると、コードは期待どおりに機能します。
ipdb> dict(fld.flatchoices).get(int(value), value)
'Mummy'
ipdb> print 'w00t'
これはすべて素晴らしいことですが、get_foo_displayメソッドがほとんどの場合正しい値を返す理由についての私の最初の質問には答えていません。ある時点で、文字列(u'1')を正しいデータ型(1)にキャストする必要があります。
[更新3]答え
名誉ある言及は彼の洞察のためにジョアオに行かなければなりませんが、賞金は私が最初に間違った価値を渡しているという率直な事実を指摘するためにジョシュに行きます。私はこれを「強い型の世界」からの移民であると言いました。そこでは、これらのことは起こり得ません!
ここに含めなかったコードは、 ChoiceFieldcleaned_data
からを使用して、オブジェクトがdjangoフォームから初期化されることです。これに伴う問題は、ChoiceFieldからの出力が整数ではなく文字列であるということです。私が見逃したのは、緩く型付けされた言語では、文字列を使用して整数プロパティを設定することが可能であり、悪いことは何も起こらないということです。
これを調べたところ、からの出力が常に整数であることを確認するために、 TypedChoiceFieldを使用する必要があることがわかりました。cleaned_data
皆さん、ありがとうございました。