How to merge multiple models in serializer/view Django REST Framework?
I'm a newbie, please don't throw me slippers. The example is degenerate, but... there is a post model with text and owner. Each post is associated with its address, so the coordinates of the post are stored in a separate table. At this stage I can create a post with coordinates by overriding the create() method.
# models.py
User = get_user_model()
class Post(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
description = models.TextField(null=False, blank=True)
class Address(models.Model):
post = models.OneToOneField(Post, on_delete=models.CASCADE)
lat = models.FloatField('Latitude', blank=True, null=True)
lng = models.FloatField('Longitude', blank=True, null=True)
# serializer.py
class AddressDetailSerializer(serializers.ModelSerializer):
class Meta:
model = Address
fields = [
'lat',
'lng',
]
class PostDetailSerializer(serializers.ModelSerializer):
owner = serializers.HiddenField(default=serializers.CurrentUserDefault())
addr_point = AddressDetailSerializer(many=False)
class Meta:
model = Post
fields = [
'id',
'description',
'owner',
'addr_point',
]
def create(self, validated_data):
addr_point_data = validated_data.pop('addr_point')
post = Post.objects.create(**validated_data)
Address.objects.create(post=post, **addr_point_data)
return post
# views.py
class PostCreateView(generics.CreateAPIView):
queryset = Post.objects.all()
serializer_class = PostDetailSerializer
Now, I am completely clueless on how to display information about each post in the following format:
{
"owner": "admin"
"description": "blablabla",
"addr_point": {
"lat": 123,
"lng": 123
}
}
None of my serializer/view variants work or output the coordinate field.
UPD: For example, I use the following view to get information about some posts:
# view.py
class PostDetailView(generics.RetrieveUpdateDestroyAPIView):
serializer_class = PostDetailSerializer
queryset = Post.objects.all()
But I get AttributeError: 'Post' object has no attribute 'addr_point'.
I'll be happy to get tips on which direction to move!
When you try to retrieve an Post
instance using it PostDetailSerializer
, it will look for the properties listed in PostDetailSerializer.Meta.fields
.
So, in addr_point
access that doesn't exist in the model post.addr_point
.
I suggest some changes:
# models.py
class Address(models.Model):
post = models.OneToOneField(Post, on_delete=models.CASCADE, related_name="address")
lat = models.FloatField('Latitude', blank=True, null=True)
lng = models.FloatField('Longitude', blank=True, null=True)
# serializers.py
class PostDetailSerializer(serializers.ModelSerializer):
owner = serializers.HiddenField(default=serializers.CurrentUserDefault())
address = AddressDetailSerializer(many=False)
class Meta:
model = Post
fields = [
'id',
'description',
'owner',
'address',
]
- In the
Address.post
field, we added therelated_name
parameter, so we can access the reverse relationship with the specified string. In this case, we can access the post's address by accessing itpost.address
. - in
PostDetailSerializer
usaddr_point
becameaddress
.post
This way, when the instance is serialized ,post.address
it actually exists.