Джанго ведет себя так, как ожидалось. Чтобы понять, почему мы начнем с рассмотрения способов передачи аргументов ключевых слов в конструктор класса модели в случае связи с внешним ключом.
Используйте имя отношения (uid_string
). В этом случае вы должны передать экземпляр связанной модели (uid_string = rootentry
).
Использовать имя поля базы данных (uid_string_id
). Здесь вы должны передать значение соответствующего типа . Поэтому, если FK указывает на целочисленное поле, передайте целое число; если он указывает на текст, передайте текстовый экземпляр и т. д.
Теперь давайте посмотрим на ваш код. Мы начнем с первой строки :
shrubentry = shrub(uid_string_id = rootentry.uid_string)
shrubentry.save() # Succeeds
Вы создали отношение между shrub
и root
, но также указали пользовательский to_field
для ссылки. Поскольку этот столбец является текстовым полем, вы можете передать rootentry.uid_string
в качестве значения аргумента ключевого слова uid_string_id
(механизм # 2 указан выше).
Существует другой способ выразить то, что вы сделали выше, без использования имени поля в качестве аргумента ключевого слова. Это будет использовать имя отношения и передать экземпляр root (механизм # 1, перечисленный выше).
shrubentry = shrub(uid_string = rootentry)
shrubentry.save() # Succeeds
Теперь давайте взглянем на вторую строку .
treeentry = tree(uid_string = rootentry.uid_string) # Raises error.
# ValueError: Cannot assign "'text'": "tree.uid_string" must be a "root" instance.
Эта строка отличается от первой строки. Вы используете механизм # 1 (имя отношения), и поэтому Django ожидает экземпляр root
в качестве значения аргумента ключевого слова. Если вы переключаетесь на механизм # 2 (имя поля):
treeentry = tree(uid_string_id = rootentry.uid_string)
treeentry.save() # Succeeds
Теперь самое интересное. Попробуйте это:
treeentry = tree(uid_string_id = rootentry.id) # No problem
treeentry.save() # Blows up
# IntegrityError: ...
# DETAIL: Key (uid_string)=(2) is not present in table "app_root".
Первая строка приведенного выше фрагмента работает. Но когда вы пытаетесь сохранить его, база данных ищет ключ «2» (т.е. rootentry.id
) в столбце _uid_string_ таблицы root
. Так как его там нет, save()
терпит неудачу.