1

this is a follow-up to this question I had here.

I can now POST a new AP object using user Primary Key and after commenting this line in the AP serializer user = UserIndexSerializer():

Postman request:

{
    "user":1,
    "name":"Max AP 05"
}

However the problem that I now have is that the initial UserIdexSerializer is rendered useless.

This serializer determines the fields to show in a GET request but in consequence imposes the fields required in a POST request. What I'm trying to do is:

  • POST a new AP object only using the user ID
  • Show the UserIndexSerializer fields during a GET request (first_name, last_name, but not the ID)

How can I make this work?

I have found and read this post.

I tried using different views, one for listing my models and one for creating a new one:

from rest_framework import serializers
from ..models.model_art_piece import AP
from .serializers_user import *


class APIndexSerializer(serializers.ModelSerializer):
    user = UserIndexSerializer()

    class Meta:
        model = AP
        fields = [
            'id',
            'user',
            'name'
        ]

class APCreateSerializer(serializers.ModelSerializer):
    user = UserIDSerializer()

    class Meta:
        model = AP
        fields = [
            'id',
            'user',
            'name'
        ]

    def create(self, validated_data):
        ap = AP.objects.create(**validated_data)
        return ap

class APDetailsSerializer(serializers.ModelSerializer):
    class Meta:
        model = AP
        fields = '__all__'

And I also tried creating different serializers:

from rest_framework import serializers
from ..models.model_user import User


class UserIndexSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = [
            'first_name',
            'last_name'
        ]

class UserIDSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = [
            'id'
        ]

class UserDetailsSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = '__all__'

This has not work at all, can anyone help me out with this?

MaxenceP
  • 291
  • 2
  • 12

2 Answers2

3

If I understood correctly what you want is to get the nested object during get. I had the same problem which I resolved with this in my serializer.

class APIndexSerializer(serializers.ModelSerializer):
    class Meta:
        model = AP
        fields = ['id','user','name']

    def to_representation(self, obj):
        self.fields['user'] = UserIndexSerializer()
        return super(APIndexSerializer, self).to_representation(obj)

You can with this create with id and get with nested information of user.

MrVhek
  • 124
  • 12
  • Just to understand better the return of the to_representation method. Is the obj passed in the to_representation(obj) the created object using the super() function, inheriting from the serializer and the current AP instance being processed? – Seb Mar 11 '20 at 03:23
2

I will give you an example to explain how to use different serializers in GET/POST for relational fields.

There is a Ticket model and it has a foreign key refers to User model. In your POST to create a ticket, you wanna user's id to create the object. In your GET to get ticket's details, you wanna show the user's details rather than ids.

Ticket(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)

In your serializer file, you then have

class UserDetailSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('first_name', 'last_name')


class TicketPostSerializer(serializer.ModelSerializer):
    class Meta:
        model = Ticket
        fields = '__all__'


class TicketDetailSerializer(serializer.ModelSerializer):
    user = UserDetailSerializer(read_only=True)
    class Meta:
        model = Ticket
        fields = '__all__'

Then, in Ticket's view function, you then have:

class TicketViewSet(viewsets.ModelViewSet):
    serializer_class = TicketPostSerializer
    def get_serializer_class(self):
        if self.action in ['list', 'retrieve']:
            return TicketDetailSerializer

All set, you are free to go.

Jun Zhou
  • 1,077
  • 1
  • 6
  • 19
  • I see what you did @JunZhou, but when i try it, it gives me the error `'AP' object has no attribute 'action'` – MaxenceP Mar 10 '20 at 00:02