Tại sao get_FOO_display() trả lại giá trị số nguyên khi thông tin ghi nhật ký (django)?Tại sao get_FOO_display() trả về giá trị số nguyên khi thông tin ghi nhật ký (django)?
Tôi có trường mô hình đang sử dụng lựa chọn để hạn chế giá trị của nó. Điều này làm việc tốt và tôi có nó hoạt động ở mọi nơi trong ứng dụng, ngoại trừ khi đăng nhập thông tin, khi phương thức get_FOO_display() trả về giá trị nguyên cơ bản thay vì của phiên bản có thể đọc được.
Đây là định nghĩa mô hình (tóm tắt):
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
)
Nếu tôi chạy này trong (django) vỏ tương tác nó cư xử chính xác như bạn mong chờ:
>>> from frankenstein.core.models import Thing
>>> thing = Thing()
>>> thing.role = 0
>>> thing.get_role_display()
u'Monster'
Tuy nhiên, khi tôi sử dụng chính xác cấu trúc tương tự trong chuỗi định dạng/ghi nhật ký tôi gặp sự cố:
logger.info('New thing: <b>%s</b>', thing.get_role_display())
lợi nhuận:
New thing: <b>0</b>
Help!
[UPDATE 1]
Khi tôi chạy khai thác gỗ bên trong vỏ tương tác tôi nhận được đầu ra chính xác:
>>> from frankenstein.core.models import Thing
>>> import logging
>>> thing = Thing()
>>> thing.role = 0
>>> logging.info('hello %s', b.get_role_display())
INFO hello Monster
[UPDATE 2] Django internals
Theo dõi trên câu trả lời từ @ joao-oliveira dưới đây, tôi đã đào vào bên trong và phát hiện ra sau đây.
Phương pháp _get_FIELD_display tiềm ẩn trong django.db.models
trông như thế này:
def _get_FIELD_display(self, field):
value = getattr(self, field.attname)
return force_unicode(dict(field.flatchoices).get(value, value), strings_only=True)
Nếu tôi đặt một breakpoint vào mã, và sau đó chạy IPdb tôi có thể thấy rằng tôi có vấn đề:
ipdb> thing.get_role_display()
u'1'
ipdb> thing._get_FIELD_display(thing._meta.get_field('role'))
u'1'
Vì vậy, sửa chữa đã không thay đổi bất cứ điều gì. Nếu tôi sau đó thử chạy qua mã _get_FIELD_display
phương pháp bằng tay, tôi có được điều này:
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'
Đó là tương đương với nói:
ipdb> {0: 'Monster', 1: 'Mummy'}.get(u'1', u'1')
u'1'
So. Vấn đề chúng tôi có là phương pháp đang sử dụng giá trị chuỗi u'1'
để tra cứu mô tả tương ứng trong từ điển lựa chọn, nhưng các phím từ điển là số nguyên và không phải là chuỗi. Do đó chúng tôi không bao giờ có được một trận đấu, nhưng thay vào đó là giá trị mặc định, được đặt thành giá trị hiện tại (chuỗi).
Nếu tôi tự buộc các diễn viên để int, mã làm việc như mong đợi:
ipdb> dict(fld.flatchoices).get(int(value), value)
'Mummy'
ipdb> print 'w00t'
Đây là tất cả tuyệt vời, nhưng không trả lời câu hỏi ban đầu của tôi là tại sao phương pháp get_foo_display không trả lại đúng giá trị hầu hết thời gian. Tại một số điểm, chuỗi (u'1 ') phải được truyền đến đúng kiểu dữ liệu (1).
[UPDATE 3] Câu trả lời
Trong khi một danh dự phải đến Joao cho cái nhìn sâu sắc của mình, tiền thưởng sẽ Josh đã chỉ ra một thực tế cùn rằng tôi đi qua trong giá trị sai lầm khi bắt đầu với. Tôi đặt nó xuống để trở thành một người di cư từ 'thế giới mạnh mẽ', nơi những điều này không thể xảy ra!
Mã mà tôi không đưa vào đây là đối tượng được khởi tạo từ biểu mẫu django, sử dụng số cleaned_data
từ số ChoiceField. Vấn đề với điều này là đầu ra từ một ChoiceField là một chuỗi, không phải là một số nguyên. Các bit tôi bị mất là trong một ngôn ngữ lỏng lẻo-typed nó có thể thiết lập một tài sản số nguyên với một chuỗi, và cho không có gì xấu xảy ra.
Sau khi xem xét điều này, tôi thấy rằng tôi đã sử dụng TypedChoiceField, để đảm bảo rằng đầu ra từ cleaned_data
luôn là số nguyên.
Cảm ơn tất cả.
Để rõ ràng, đây có phải là việc ghi nhật ký vào một tệp hoặc đăng nhập vào một dịch vụ (ví dụ: HipChat) không? IIRC, logger đánh giá lười biếng, và có thể không xem xét một cuộc gọi dịch vụ 'đủ' để thực sự đánh giá get_FOO_display –
Đây là đăng nhập vào một dịch vụ, qua HTTP, sử dụng các yêu cầu. –
Mã này ở đây - https://gist.github.com/3176710 –