10

I’m trying to add a ForeignKey field to a Django model using South. I’m getting the following error:

ValueError: You cannot add a null=False column without a default value.

I did, in fact, specify a default value for the field, but I’m not sure I did it correctly.

language = models.ForeignKey(Language, default=Language.objects.all()[0])

Should this work?

Paul D. Waite
  • 96,640
  • 56
  • 199
  • 270

4 Answers4

16

AFAIK Django won't execute a QuerySet passed as a param, even if it's limited to one element. You should try something like proposed in this post

class Foo(models.Model):
    a = models.CharField(max_length=10)

def get_foo():
    return Foo.objects.get_or_create(id=1)

class Bar(models.Model):
    b = models.CharField(max_length=10)
    a = models.ForeignKey(Foo, default=get_foo)
radious
  • 812
  • 6
  • 21
  • I would post the same. Additionaly you can create a default element in get_foo if Foo has no data. – balazs Aug 16 '11 at 16:00
  • 1
    Yes, using get_or_create is nice idea! – radious Aug 16 '11 at 16:06
  • 3
    This doesn't really work, assuming the only point is to query by something other than `id`. This is because the query is run before the migration is created, and the resulting `id` is hardcoded into the migration. So if anyone who later runs the migration has a different `id` for the desired record, they'll still get your `id` rather than running the query on their database, so will get a random default. – Chris Aug 25 '19 at 23:05
2

Because get_or_create returns a tuple, I think this is a better solution

def get_default():
    result, _ = Foo.objects.get_or_create(id=1)
    return result

than this

return Foo.objects.get_or_create(id=1)
Barm
  • 403
  • 5
  • 11
bopajdowski
  • 21
  • 1
  • 3
1

This is really an extension to @radious answer. You can also use lambda in the default, if you're looking to cut out lines of code

class Foo(models.Model):
    a = models.CharField(max_length=10)

class Bar(models.Model):
    b = models.CharField(max_length=10)
    a = models.ForeignKey(Foo, default=lambda: Foo.objects.get_or_create(id=1)[0])

note that you have to use index 0 on get_or_create() because the method returns a tuple, so you need to get the object, instead of the tuple.

https://docs.djangoproject.com/en/1.6/ref/models/querysets/#get-or-create

Josh Brown
  • 925
  • 11
  • 13
  • 3
    Django can't serialize lambda expressions – QuestionEverything May 23 '17 at 12:34
  • 3
    The relevance of @HasanIqbal's comment is this means this approach won't work after Django 1.7 (assuming you're using migrations) - [docs](https://docs.djangoproject.com/en/1.7/topics/migrations/#serializing-values) – Chris Aug 25 '19 at 22:42
0

You should use get_or_create() and models.ForeignKey() needs on_delete as shown below. *Don't forget to put .id just after get_or_create(id=1)[0] because default in models.ForeignKey() needs id of a Language object otherwise there is an error:

language = models.ForeignKey(
    Language,               # Here  
    default=Language.objects.get_or_create(id=1)[0].id),
    on_delete=models.CASCADE # Here
)
Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129