Question
With Django REST Framework, a standard ModelSerializer will allow ForeignKey model relationships to be assigned or changed by POSTing an ID as an Integer.
What's the simplest way to get this behavior out of a nested serializer?
Note, I am only talking about assigning existing database objects, not nested creation.
I have hacked away around this in the past with additional 'id' fields in the
serializer and with custom create
and update
methods, but this is such a
seemingly simple and frequent issue for me that I'm curious to know the best
way.
class Child(models.Model):
name = CharField(max_length=20)
class Parent(models.Model):
name = CharField(max_length=20)
phone_number = models.ForeignKey(PhoneNumber)
child = models.ForeignKey(Child)
class ChildSerializer(ModelSerializer):
class Meta:
model = Child
class ParentSerializer(ModelSerializer):
# phone_number relation is automatic and will accept ID integers
children = ChildSerializer() # this one will not
class Meta:
model = Parent
Answer
The best solution here is to use two different fields: one for reading and the other for writing. Without doing some heavy lifting, it is difficult to get what you are looking for in a single field.
The read-only field would be your nested serializer (ChildSerializer
in this
case) and it will allow you to get the same nested representation that you are
expecting. Most people define this as just child
, because they already have
their front-end written by this point and changing it would cause problems.
The write-only field would be a [PrimaryKeyRelatedField
](http://www.django-
rest-framework.org/api-guide/relations/#primarykeyrelatedfield), which is what
you would typically use for assigning objects based on their primary key. This
does not have to be write-only, especially if you are trying to go for
symmetry between what is received and what is sent, but it sounds like that
might suit you best. This field should have [a source
](http://www.django-
rest-framework.org/api-guide/fields/#source) set to the foreign key field
(child
in this example) so it assigns it properly on creation and updating.
This has been brought up on the discussion group a few times, and I think this is still the best solution. Thanks to [Sven Maurer for pointing it out](https://groups.google.com/d/msg/django-rest- framework/XBJztipJsYE/5_JFFzrHcJQJ).