Джанго, гипнотизер

amused emoticon

Нет, конечно не вот этот Джанго а вот этот.

Так вот, вчера я поймал себя на совершенно эпическом баге которым грех не поделиться, потому что в силу особенностей местонахождения, он чуть было не стоил мне кучи неприятностей и насмерть утерянных данных.

Итак, сижу я, ковыряю код, а посреди он вдруг спотыкается и вываливает мне exception, подавившись вот этой строчкой:


{'work_login': u'sch771231'}

Как вы думаете, что здесь не так?

Итак, у нас в базе есть TextField, в котором хранится json. Так надо, потому что в исходной базе с которой я работаю и от которой отвертеться никак не могу там тоже json, и вообще, до тех пор пока вы не парсите этот json каждый раз когда обращаетесь к полю, это относительно нормальная практика.

Прочитывая питоновский dictionary из джанговского поля TextField, я естественно не забыл сказать ему json.loads(field). Но забыл сказать json.dumps(dictionary) при записи обратно. Django, как будто так и надо, с чистой совестью положил туда dictionary.__str__ То бишь загипнотизировал словарь до полного строкового представления.

То что выводит представление словаря-как-строки – очень похоже на json, поэтому визуально разглядывая результат я ничего не заметил. Но json – это запись объекта по правилам синтаксиса javascript, а питоновское dictionary.__str__ – это запись словаря по правилам синтаксиса Python, и при попытке json.loads() на результат оно подавится почти всегда.

Все вскрылось только потому, что я нашел полезный класс JSONField который работает с таким полем сразу как со словарем, и попытался заменить TextField на JSONField.

Самое изящное: В результате, починка бага свелась к неизменению той строки, в которой он на самом деле был.

Мораль: Строгая типизация спасла бы меня от этой проблемы и многих других.