Search code examples
pythondjangodjango-rest-frameworkdjango-serializer

Django Rest Framework two Serializers for the same Model


I'm pretty sure there's a better way to do this:

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = ('category', 'id', 'title', 'image', 'slug', 'author', 'excerpt', 'content', 'status', 'published')


class FrontendPostSerializer(serializers.ModelSerializer):
    author = AuthorSerializer(many=False, read_only=True)
    category = CategorySerializer(many=False, read_only=True)

    class Meta:
        model = Post
        fields = ('category', 'id', 'title', 'image', 'slug', 'author', 'excerpt', 'content', 'status', 'published')

PostSerializer is gonna look like this

    {
        "category": 1,
        "id": 45,
        "title": "Lorem Ipsum - Lorem ipsum dolor sit amet consectetur",
        "image": "http://localhost:8000/media/posts/car_SxXcUTV.jpg",
        "slug": "lorem-ipsum-lorem-ipsum-dolor-sit-amet-consectetur",
        "author": 4,
        "excerpt": "Officiis iure rerum voluptates a cumque velit \nquibusdam sed amet tempora. Sit laborum ab, eius fugit doloribus tenetur \nfugiat, temporibus enim commodi iusto libero magni deleniti quod quam \nconsequuntur! Commodi minima excepturi repudiandae velit hic maxime\ndoloremque.",
        "content": "Officiis iure rerum voluptates a cumque velit \nquibusdam sed amet tempora. Sit laborum ab, eius fugit doloribus tenetur \nfugiat, temporibus enim commodi iusto libero magni deleniti quod quam \nconsequuntur! Commodi minima excepturi repudiandae velit hic maxime\ndoloremque.",
        "status": "published",
        "published": "2021-10-01T14:46:34.872576Z"
    }

FrontendPostSerializer is gonna look like this

{
        "category": {
            "name": "django"
        },
        "id": 45,
        "title": "Lorem Ipsum - Lorem ipsum dolor sit amet consectetur",
        "image": "http://localhost:8000/media/posts/car_SxXcUTV.jpg",
        "slug": "lorem-ipsum-lorem-ipsum-dolor-sit-amet-consectetur",
        "author": {
            "username": "luigi.verdi"
        },
        "excerpt": "Officiis iure rerum voluptates a cumque velit \nquibusdam sed amet tempora. Sit laborum ab, eius fugit doloribus tenetur \nfugiat, temporibus enim commodi iusto libero magni deleniti quod quam \nconsequuntur! Commodi minima excepturi repudiandae velit hic maxime\ndoloremque.",
        "content": "Officiis iure rerum voluptates a cumque velit \nquibusdam sed amet tempora. Sit laborum ab, eius fugit doloribus tenetur \nfugiat, temporibus enim commodi iusto libero magni deleniti quod quam \nconsequuntur! Commodi minima excepturi repudiandae velit hic maxime\ndoloremque.",
        "status": "published",
        "published": "2021-10-01T14:46:34.872576Z"
    }

What I'm doing atm is using FrontendPostSerializer for showing data in the frontend, for example in a table with category name, author name and title. Instead, I'm using PostSerializer for the backend CRUD.

These are the viewsets I'm using in the views.py

class ManagePosts(viewsets.ModelViewSet):
    serializer_class = PostSerializer
    parser_classes = [MultiPartParser, FormParser]

    def get_object(self, queryset=None, **kwargs):
        item = self.kwargs.get('pk')
        return get_object_or_404(Post, slug=item)

    # Define Custom Queryset
    def get_queryset(self):        
        return Post.objects.all()

class FrontendPosts(viewsets.ModelViewSet):
    serializer_class = FrontendPostSerializer

    def get_object(self, queryset=None, **kwargs):
        item = self.kwargs.get('pk')
        return get_object_or_404(Post, slug=item)

    # Define Custom Queryset
    def get_queryset(self):        
        return Post.objects.all()

I already tried to use only one serializer, I had this:

class PostSerializer(serializers.ModelSerializer):
    author = AuthorSerializer(many=False, read_only=True)
    category = CategorySerializer(many=False, read_only=True)

    class Meta:
        model = Post
        fields = ('category', 'id', 'title', 'image', 'slug', 'author', 'excerpt', 'content', 'status', 'published')

but, for example, when I try to create a new post it doesn't work, because category and author are not numbers, but objects.

I'm also gonna put here create.js I have in my React frontend that handles the create submit.

    const handleSubmit = (e) => {
        e.preventDefault();
        let formData = new FormData();
        formData.append('category', 1);
        formData.append('title', postData.title);
        formData.append('slug', postData.slug);
        formData.append('author', userInfo.id);
        formData.append('excerpt', postData.excerpt);
        formData.append('content', postData.content);
        if(postImage.image !== null) {
            formData.append('image', postImage.image);
        } 
        axiosInstance.post('', formData);
        history.push({
            pathname: '/admin/',
        });
        window.location.reload();
    };

Is there a better way? I'm sure I can use only one serializer, but I'm not sure how yet.

Thanks!


Solution

  • Actually yes. You can add specific fields you want by using the source attribute. Example:

    class PostSerializer(serializers.ModelSerializer):
       authorUserName = serializers.CharField(read_only=true, source="author.username")
       categoryName = serializers.CharField(read_only=true, source="category.name"
    
       class Meta:
          model = Post
          fields = (
             'category', 'id', 'title',
             'image', 'slug', 'author',
             'excerpt', 'content', 'status',
             'published', 'authorName', 'categoryName')
    
             # Remember add the field that are created
    

    And when you try to get you should get the result like this:

    {
        "categoryName": "django",
        "category": 1,
        "id": 45,
        "title": "Lorem Ipsum - Lorem ipsum dolor sit amet consectetur",
        "image": "http://localhost:8000/media/posts/car_SxXcUTV.jpg",
        "slug": "lorem-ipsum-lorem-ipsum-dolor-sit-amet-consectetur",
        "authorName": "luigi.verdi",
        "author": 4,
        "excerpt": "Officiis iure rerum voluptates a cumque velit \nquibusdam sed amet tempora. Sit laborum ab, eius fugit doloribus tenetur \nfugiat, temporibus enim commodi iusto libero magni deleniti quod quam \nconsequuntur! Commodi minima excepturi repudiandae velit hic maxime\ndoloremque.",
        "content": "Officiis iure rerum voluptates a cumque velit \nquibusdam sed amet tempora. Sit laborum ab, eius fugit doloribus tenetur \nfugiat, temporibus enim commodi iusto libero magni deleniti quod quam \nconsequuntur! Commodi minima excepturi repudiandae velit hic maxime\ndoloremque.",
        "status": "published",
        "published": "2021-10-01T14:46:34.872576Z"
    }