Setting default value for Foreign Key attribute in Django

As already implied in @gareth’s answer, hard-coding a default id value might not always be the best idea:

If the id value does not exist in the database, you’re in trouble. Even if that specific id value does exist, the corresponding object may change. In any case, when using a hard-coded id value, you’d have to resort to things like data-migrations or manual editing of existing database content.

To prevent that, you could use get_or_create() in combination with a unique field (other than id).

Here’s one way to do it:

from django.db import models

 
class Exam(models.Model):
    title = models.CharField(max_length=255, unique=True)
    description = models.CharField(max_length=255)
    
    @classmethod
    def get_default_pk(cls):
        exam, created = cls.objects.get_or_create(
            title="default exam", 
            defaults=dict(description='this is not an exam'),
        )
        return exam.pk
    
    
class Student(models.Model):
    exam_taken = models.ForeignKey(
        to=Exam, on_delete=models.CASCADE, default=Exam.get_default_pk
    )

Here an Exam.title field is used to get a unique object, and an Exam.description field illustrates how we can use the defaults argument (for get_or_create) to fully specify the default Exam object.

Note that we return a pk, as suggested by the docs:

For fields like ForeignKey that map to model instances, defaults should be the value of the field they reference (pk unless to_field is set) instead of model instances.

Also note that default callables are evaluated in Model.__init__() (source). So, if your default value depends on another field of the same model, or on the request context, or on the state of the client-side form, you should probably look elsewhere.

Leave a Comment

File not found.