Django ForeignKey TypeError только в миграциях (поле "id" ожидало число, а получило <Model Instance>")
Итак, у меня есть модель User, которая имеет ForeignKey для хранения отдела, к которому он принадлежит. Это что-то вроде этого:
class Department(models.Model):
name = models.CharField(max_length=250)
...
class User(models.Model):
...
department = models.ForeignKey(Department, on_delete=models.CASCADE, null=True, blank=True)
...
И у меня есть несколько зарегистрированных пользователей. Но так или иначе, я получил задание сделать так, что теперь опция отдела больше не является опциональной, она должна быть обязательной, и если пользователь не выбирает отдел, система должна использовать отдел по умолчанию, поэтому я сделал текущие изменения, используя функцию для получения или создания отдела по умолчанию:
def get_default_department():
try:
default_department = Department.objects.get(name="Default")
except Department.DoesNotExist:
default_department = Department.objects.create(name="Default", ...)
return default_department
И добавление функции в качестве параметра по умолчанию в атрибут "department" моей модели User (а также изменение опций null и blank на False):
class User(models.Model):
department = models.ForeignKey(Department, on_delete=models.CASCADE, null=False, blank=False, default=get_default_department)
Ок, отлично, затем я запустил makemigrations и все работало хорошо, пока я не запустил команду migrate, которая привела меня к следующему сообщению об ошибке: "TypeError: Поле 'id' ожидало число, но получило <Department: Default>"
Просто взглянув на него, я понял, что проблема была в том, что моя функция возвращала экземпляр модели департамента вместо его первичного ключа, поэтому мне пришлось внести следующие изменения в мою функцию:
def get_default_department():
try:
default_department = Department.objects.get(name="Default").pk
except Department.DoesNotExist:
default_department = Department.objects.create(name="Default", ...).pk
return default_department
PS: я знаю, что мог бы просто вернуть пк напрямую с помощью "return default_department.pk", но я торопился, поэтому не обращайте внимания на id, пожалуйста.
В любом случае, это изменение решило мою проблему. Мой вопрос в том, почему я должен был это делать? Насколько я знаю, Django достаточно умен, чтобы понять, что возвращаемый экземпляр должен быть внешним ключом, верно? Я делал это тысячи раз, мне никогда не требовалось возвращать pk явно. И я даже подтвердил это, удалив .pk из моей функции, когда я уже сделал миграцию, и она работала прекрасно, так почему же проблема возникает только при миграции?
это может сработать для вас, если ваш код в порядке, проверьте другой конфиг один раз
удалите миграцию и попробуйте следующее
def get_default_department():
default_department, _ = Department.objects.get_or_create(name="Default")
return default_department.pk
Скорее всего, это связано с тем, как устроен Django ORM. ForeignKeys в Django работают с id модели, а не со всем экземпляром модели, поэтому указание, что это id модели, позволяет правильно перевести его в SQL запросы. Не знаю, имеет ли это смысл.
В документации сказано следующее: "Для полей типа ForeignKey, которые отображаются на экземпляры модели, значениями по умолчанию должно быть значение поля"
Подробнее читайте здесь: https://docs.djangoproject.com/en/4.1/ref/models/fields/
В разделе "default"