Django и пустые значения
Допустим, у вас в приложении есть сущность «Клиент», а у клиента поле «Имя». Клиенты указывают имя при регистрации, но поскольку это не обязательно — многие предпочитают оставлять поле пустым. Как в таких случаях должно имя храниться в базе данных?
Я всегда полагал, что на этот вопрос может быть единственный ответ — использовать специальное значение NULL
. Оно ведь ровно для этого и предназначено: показать, что поле не заполнено, его значение неизвестно.
NULL vs пустая строка
Создатели «Джанги», однако, пошли против вековой мудрости разработчиков, и норовят сохранять отсутствующее значение как пустую строку. За это отвечает специальная настройка (null=False
). Менять её не рекомендуют — мол, путаница от этого возникнет:
If
True
, Django will store empty values asNULL
in the database. Default isFalse
.
Avoid using
null
on string-based fields because empty string values will always be stored as empty strings, not asNULL
.
If a string-based field has
null=True
, that means it has two possible values for “no data”:NULL
, and the empty string. In most cases, it’s redundant to have two possible values for “no data”; the Django convention is to use the empty string, notNULL
.
Этот кусок документации заслуживает особой похвалы. Так всё запутать, ничего толком не объяснив — это ещё надо суметь. Следите за руками:
- с одной стороны, «if True, Django will store empty values as NULL»,
- одновременно с этим «empty string values will always be stored as empty strings, not as NULL».
Так вы храните пустые значения как NULL при включённой настройке? Или всегда-всегда как пустую строку (и на кой чёрт тогда настройка)? Определитесь уже!
На самом деле, авторы имели в виду следующее:
- Если
null=False
, и вы не присвоите полю значение, «Джанга» молча присвоит ему""
и сохранит в базе как пустую строку. - Если
null=True
, и вы не присвоите полю значение, «Джанга» молча присвоит емуNone
и сохранит в базе какNULL
. - Вне зависимости от настройки, если вы явно присвоите полю значение
""
, «Джанга» сохранит его в базе как пустую строку. - Вне зависимости от настройки, если вы явно присвоите полю значение
None
, «Джанга» сохранит его в базе какNULL
.
Ох.
NOT NULL на таблице
Но это полбеды. О чём авторы совсем забыли упомянуть в документации — о том, что null=False
генерирует такой SQL-код:
ALTER TABLE "tablename"
ADD COLUMN "columnname" varchar (50) DEFAULT '' NOT NULL;
То есть не просто «мы будем записывать неизвестное значение в базу как пустую строку», а «мы вообще запретим этому полю иметь значение NULL
».
Это очень, очень творческое дизайнерское решение. Дело в том, что если у вас таблица на 100000 строк, и вы добавляете в неё NOT NULL
столбец, то это, мягко говоря, небыстро. И полностью блокирует таблицу на всё время операции.
А если приложение развивается, новые столбцы добавляют регулярно. И с NOT NULL
каждый раз при миграции таблица блокируется и полностью перезаписывается. Как вообще можно было додуматься до такого подхода?
Чтобы решить проблему, достаточно игнорировать рекомендации «Джанги» и ставить текстовым полям null=True
.
P.S. В PostgreSQL 11 добавили специальную оптимизацию, благодаря которой добавление NOT NULL
столбца работает моментально, если у него есть значение по умолчанию. Так что в новом «Постгресе» рекомендуемые настройки «Джанги» наконец-то перестали стрелять в ногу разработчикам.
Подписывайтесь на канал, чтобы не пропустить новые заметки 🚀