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"

Вернуться на верх