ForeignKey does not allow null values
Django Rest-FrameworkModelForeign KeysSerializationDjango Rest-Framework Problem Overview
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
-
The multipart form is rendered in the browser with empty choice for
assigned_to
field. -
When posting raw JSON, I get the following error message:
Cannot assign None: "Mission.assigned_to" does not allow null values.
Django Rest-Framework Solutions
Solution 1 - Django Rest-Framework
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:
- Validator(controlled by
blank
) - 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).
Solution 2 - Django Rest-Framework
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
Solution 3 - Django Rest-Framework
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
Solution 4 - Django Rest-Framework
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.