Django ForeignKey TypeError only in migrations (Field "id" expected a number but got <Model Instance>")

So i have a User model which has a ForeignKey to store the Department from where it belongs. It is something like this:

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)
    ...

And i have some users registered. But anyways, i got the task to make it so that now the department option is no longer optional, it must be obligatory, and if the user doesn't choose one, the system must use a Default one, so i made the current changes by using a function to get or create the Default department:

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

And adding the function as the default parameter on my User model "department"'s attribute (as well as changing the null and blank options to False):

class User(models.Model):
    department = models.ForeignKey(Department, on_delete=models.CASCADE, null=False, blank=False, default=get_default_department)

Ok, perfect, then i ran makemigrations and everything worked well, until i ran the migrate command, wich resulted me in the following error message: "TypeError: Field 'id' expected a number but got <Department: Default>"

Just by looking at it, i understood that the problem was that my function was returning an instance of the Department's model instead of its primary key, so i had to make the following change to my function:

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: i know i could have just returned the pk directly with "return default_department.pk" but i was in a hurry, so dont mind id please.

Anyway, that change solved my problem. My question is... why did i had to do it? As far as i know, Django is smart enough to understand that the instance returned was eligebly to be a foreign key right? I've done it thousands of times, i never really needed to return the pk explicitely. And i even confirmed it by removing the .pk from my function when i already had make the migrations and it ran perfectly well, so why the problem only happens when i migrate?

this could work for you other your code is fine check other config once

delete the migration and try this

def get_default_department():
    default_department, _ = Department.objects.get_or_create(name="Default")
    return default_department.pk

It's most likely something to do with how Django ORM is. ForeignKeys in Django work with the id of the model, not the whole instance of a model, so specifying that it's the id of a model allows it to properly translate it to SQL queries. I don't know if that makes sense.

It says this in the documentation: "For fields like ForeignKey that map to model instances, defaults should be the value of the field"

Read more here: https://docs.djangoproject.com/en/4.1/ref/models/fields/
Under "default"

Back to Top