Во время первого слияния строка не существует, поэтому она создается:
record = {'id': 1, 'field': None, 'field2': 3}
session.merge(TestTable(**record))
... испускается:
INSERT INTO test_table (id, field, field2) VALUES (%(id)s, %(field)s, %(field2)s)
{'id': 1, 'field': 'Unknown', 'field2': 3}
Per документация , параметр default
для Column
применяется к insert , поэтому вы можете видеть, что None
был заменен на 'Unknown'
в наборе параметров, отправленном вместе свставить заявление. Состояние документа:
Скалярное выражение, вызываемое по Python или ColumnElement
выражение, представляющее значение по умолчанию для этого столбца, которое будет вызываться при вставке, если этот столбец в противном случае не указан в предложении VALUESвставка.
... поэтому в этом случае кажется, что «не указано» следует интерпретировать как «не None
», поскольку вы явно «указали» значение в вашем record
дикт. Относительно этого является то, что когда вы создаете экземпляр без предоставления каких-либо значений для каких-либо атрибутов, эти атрибуты уже неявно содержат значение None
:
print(TestTable().field is None) # True
Если вы удалите default=...
kwarg из вашего столбцаопределение, даже если вы предоставляете field=None
в свой конструктор TestTable
, со значением по умолчанию, удаленным, значение для этого параметра вообще не отправляется в базу данных:
INSERT INTO test_table (id, field2) VALUES (%(id)s, %(field2)s)
{'id': 1, 'field2': 3}
В этом случаепо умолчанию на стороне сервера будет срабатывать. Поэтому перед сбросом оператора вставки SQLAlchemy будет заменять любые None
значения столбцов, для которых на стороне клиента по умолчанию задано значение.
При втором слиянии строка уже существует в базе данных, поэтомузначения объединенного экземпляра заполняются в экземпляре, который представляет строку, которая уже существует в базе данных. Во время слияния значение столбца field
в этом экземпляре изменяется с 'Unknown'
на None
. Это изменение значения означает, что новое значение этого поля будет отправлено в базу данных как часть запроса update . Обратите внимание, что ни операторы по умолчанию на стороне клиента, ни на стороне сервера не применяются к оператору обновления.
UPDATE test_table SET field=%(field)s WHERE test_table.id = %(test_table_id)s
{'field': None, 'test_table_id': 1}
Поскольку мы пытаемся явно установить для столбца NOT NULL
значение NULL
, значение IntegrityError
увеличивается.