What is the best way to set a default value for a foreign key field in a model? Suppose I have two models, Student
and Exam
with student having
I would modify @vault's answer above slightly (this may be a new feature). It is definitely desirable to refer to the field by a natural name. However instead of overriding the Manager
I would simply use the to_field
param of ForeignKey
:
class Country(models.Model):
sigla = models.CharField(max_length=5, unique=True)
def __unicode__(self):
return u'%s' % self.sigla
class City(models.Model):
nome = models.CharField(max_length=64, unique=True)
nation = models.ForeignKey(Country, to_field='sigla', default='IT')
the best way I know is to use lambdas
class TblSearchCase(models.Model):
weights = models.ForeignKey('TblSearchWeights', models.DO_NOTHING, default=lambda: TblSearchWeights.objects.get(weight_name='value_you_want'))
so you can specify the default row..
default=lambda: TblSearchWeights.objects.get(weight_name='value_you_want')
You could use this pattern:
class Other(models.Model):
DEFAULT_PK=1
name=models.CharField(max_length=1024)
class FooModel(models.Model):
other=models.ForeignKey(Other, default=Other.DEFAULT_PK)
Of course you need to be sure that there is a row in the table of Other
. You should use a datamigration to be sure it exists.
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 how I would 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
unlessto_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.
In my case, I wanted to set the default to any existing instance of the related model. Because it's possible that the Exam
with id 1
has been deleted, I've done the following:
class Student(models.Model):
exam_taken = models.ForeignKey("Exam", blank=True)
def save(self, *args, **kwargs):
try:
self.exam_taken
except:
self.exam_taken = Exam.objects.first()
super().save(*args, **kwargs)
If exam_taken
doesn't exist, django.db.models.fields.related_descriptors.RelatedObjectDoesNotExist
will be raised when a attempting to access it.
I'm looking for the solution in Django Admin, then I found this:
class YourAdmin(admin.ModelAdmin)
def get_changeform_initial_data(self, request):
return {'owner': request.user}
this also allows me to use the current user.
see django docs