I have three models with foreign keys in this direction Order -> Customer -> User
. I would like to write a view set for orders that serializes the corresponding user without the intermediate customer.
Models:
class Order(models.Model):
customer = ForeignKey("customers.Customer")
class Customer(models.Model):
user = ForeignKey("users.User")
class User(models.Model):
name = CharField(max_length=64)
Serializer:
class UserSerializer(ModelSerializer):
class Meta:
model = User
fields = ["name"]
class OrderSerializer(ModelSerializer):
user = UserSerializer(source="customer__user", read_only=True)
class Meta:
model = Order
fields = ["id", "user"]
View set:
class OrderViewSet(ModelViewSet):
queryset = Order.objects.all()
serializer_class = OrderSerializer
Desired output:
[
{"id": 1, "user": {"name": "John"}},
{"id": 2, "user": {"name": "Mary"}},
]
Actual output:
[
{"id": 1},
{"id": 2},
]
It works fine if I go via the intermediate customer serializer:
class CustomerSerializer(ModelSerializer):
user = UserSerializer(read_only=True)
class Meta:
model = User
fields = ["user"]
class OrderSerializer(ModelSerializer):
customer = CustomerSerializer(read_only=True)
class Meta:
model = Order
fields = ["id", "customer"]
but then the output contains the intermediate customer object:
[
{"id": 1, {"customer": {"user": {"name": "John"}}},
{"id": 2, {"customer": {"user": {"name": "Mary"}}},
]
The source
uses dot-syntax, so:
class UserSerializer(ModelSerializer):
class Meta:
model = User
fields = ['name']
class OrderSerializer(ModelSerializer):
user = UserSerializer(source='customer.user', read_only=True)
class Meta:
model = Order
fields = ['id', 'user']
I would also advise to use .select_related(..)
in the viewset, to prevent fetching the Customer
and User
with additional queries, so:
class OrderViewSet(ModelViewSet):
queryset = Order.objects.select_related('customer__user')
serializer_class = OrderSerializer