76

I am using the Django REST Framework 2.0.

Here is my model class:

class Mission(models.Model):
  assigned_to = models.ForeignKey('auth.User',
                                   related_name='missions_assigned',
                                   blank = True)

Here is my view class:

class MissionList(generics.ListCreateAPIView):
    model = Mission
    serialize_class = MissionSerializer
  1. The multipart form is rendered in the browser with empty choice for assigned_to field.

  2. When posting raw JSON, I get the following error message:

Cannot assign None: "Mission.assigned_to" does not allow null values.

Akshat Zala
  • 710
  • 1
  • 8
  • 23
Benjamin Toueg
  • 10,511
  • 7
  • 48
  • 79

4 Answers4

155

The blank option is used in the form validation, and the null is used when writing to database.

So you might add null=True to that field.

EDIT: continue the comment

Considering the two steps when saving object:

  1. Validator(controlled by blank)
  2. Database limitation(controlled by null)

For default option, take IntegerField for example,
default=5, blank=True, null=False, pass (1) even if you didn't assign a value(having blank=True), pass (2) because it has a default value(5) and writes 5 instead of None to DB.
blank=True, null=False, which pass (1) but not (2), because it attempts to write None to DB.

Thus, if you want to make a field optional, use either default=SOMETHING, blank=True, null=False or blank=True, null=True.

Another exception is the string-like field, such as CharField.
It's suggested that use the blank=True alone, leaving null=False behind.
This makes a field either a string(>=1 char(s)) or a empty string('', with len()==0), and never None.

The reason is that when null=True is set, there will be two possible value for the state "unset": empty string and None, which is confusing(and might causing bugs).

pjw91
  • 1,745
  • 1
  • 11
  • 8
  • Which means `blank = True` must always be used with `null = True`? Why can't I choose empty in my form? I did use `blank = True`. – Benjamin Toueg May 16 '13 at 13:49
  • 1
    `assigned_to==None` passed the form validator, but not database. Without `null=True`, you cannot write `None` into database. Thus, generally, if you want an optional field, set both `blank` and `null` to `True`. – pjw91 May 16 '13 at 14:11
  • 2
    However, there're two exceptions, `default` option and string-like fields. (I'd like to add after the post, instead of here, the comment.) – pjw91 May 16 '13 at 14:14
  • 1
    I'd just like to point out that `null` can also affect behaviour behind DB restrictions (see https://code.djangoproject.com/ticket/12708) – rtpg Oct 06 '14 at 07:20
  • This [link](https://stackoverflow.com/questions/8609192/differentiate-null-true-blank-true-in-django) will be helpful for `blank and null` – Cheney Jun 25 '18 at 02:28
  • The default=SOMETHING is what I was missing – M.C Jul 28 '20 at 09:28
26

ForeignKey allows null values if this behavior was set. Your code will look like this:

class Mission(models.Model):
    assigned_to = models.ForeignKey(
        'auth.User',
        related_name='missions_assigned',
        blank=True,
        null=True
    )

You have to write null=True.

Note: after you change a model, you need to run python manage.py makemigrations yourappname and then python manage.py migrate

Vukašin Manojlović
  • 3,717
  • 3
  • 19
  • 31
shmakovpn
  • 751
  • 9
  • 10
  • When updating existing model it will result in error. There are some ways to get through it, the simpliest is to delete existing database. See example solution there:https://coderbook.com/@marcus/add-new-non-null-foreign-key-to-existing-django-model/ – Jakub Jabłoński Dec 04 '19 at 19:34
  • @JakubJabłoński can you elaborate on why it will result in an error? Making a `ForeignKey` nullable and migrating is a common operation and should not give any error. I do that all the time. – sox supports the mods Feb 07 '20 at 16:43
  • @JakubJabłoński You might be thinking of this for the reverse case, moving a model from "null is allowed" to "must have a value", in which case adding a manual migration to provide default values or starting from scratch, as you suggested, would be a solution. The solution discussed above, though, has no problem. – John Q Mar 03 '20 at 20:44
7

The solution with changing the model and allowing for null with:

blank=True,
null=True

wasn't enough for me.

I was able to solve the issue by setting required in the serializer to false, e.g.

field = MyModelSerializer(required=False)

as described here (Django ForeignKey field required despite blank=True and null=True).

I ended up doing both. Allowing for null with blank=True, null=True in the model and not requiring the field in the serializer by required=False

fsulser
  • 853
  • 2
  • 10
  • 34
2

In my case, required=False wasn't enough. I needed allow_null in the serializer, per Django ForeignKey field required despite blank=True and null=True.

Paul Schreiber
  • 12,531
  • 4
  • 41
  • 63