Really Struggling with Serializers (One class that does two jobs??)

Trying to learn DRF coming from the node.js world and I’m really stuck on serializers and model serializers. It’s like one class that does both schema validation and creating / updating models too. I feel I should be making one serializer for creating objects and another serializer to define a specific output.

In my test project I have a simple Posts and Comments model, each Comment is attached to a Post and a User has many posts (pretty basic data model). What serializers should I create for this? I was thinking:

  • PostDetailSerializer:
class PostDetailSerializer(serializers.ModelSerializer):
    author = UserSerializer(read_only=True)
    comments = CommentSerializer(read_only=True, many=True, required=False)

    class Meta:
        model = models.Post
        fields = ['uuid', 'text', 'author', 'comments', 'pins', 'date_created']
        read_only_fields = ['uuid', 'pins', 'date_created']
  • CommentSerializer:
class CommentSerializer(serializers.ModelSerializer):
    author = UserSerializer(read_only=True)
    post = serializers.SlugRelatedField(slug_field='uuid', read_only=True)

    class Meta:
        model = models.Comment
        fields = ['uuid', 'text', 'date_created', 'post', 'author']
        read_only_fields = ['date_created', 'uuid']

But then I’m confused about how I protect the updating of the fields. Like I don’t want to just run is_valid and then save because then a user would be able to add a comment as another user right?

I’ll try to give a suggestion and then maybe you can describe what the suggestion would lack compared to what you want to do. That might help to understand exactly what it is you want to do. Sorry if I’m completely off the mark here but hopefully it’ll help.

What if you’d just do this:

class PostModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Post
        fields = ['uuid', 'text', 'author', 'comments', 'pins', 'date_created']

class CommentModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Comment
        fields = ['uuid', 'text', 'date_created', 'post', 'author']

And you could have a permissions.py file with say (assuming you want admins to be able to change any post/comment)

from rest_framework.permissions import BasePermission, SAFE_METHODS


class IsPostAuthorOrAdminOrReadOnly(BasePermission):
    """
    Allows access only to admin users or the author of the Post instance
    the request is about (unless it's a read-only HTTP method).
    """

    def has_object_permission(self, request, view, obj):
        is_safe_method = bool(request.method in SAFE_METHODS)
        is_author = bool(request.user and obj.author==request.user)
        is_admin = bool(request.user and request.user.is_staff)
        return is_safe_method or is_author or is_admin

And then finally you would have views like say

from rest_framework.generics import RetrieveUpdateDestroyAPIView
from .serializers import PostModelSerializer, CommentModelSerializer
from .models import Post, Comment

class PostDetailView(RetrieveUpdateDestroyAPIView):
    serializer_class = PostModelSerializer
    queryset = Post.objects.all()
    permission_classes = (IsPostAuthorOrAdminOrReadOnly,)

class CommentDetailView(RetrieveUpdateDestroyAPIView):
    serializer_class = CommentModelSerializer
    queryset = Comment.objects.all()
    permission_classes = (IsPostAuthorOrAdminOrReadOnly,)

The part with the permissions would answer this question (assuming I understood it correctly), I think:

But then I’m confused about how I protect the updating of the fields.

You can read more about DRF’s Permissions here.

Again, this is just a suggestion. What functionality would be missing if you only did this? Your answer will probably help clarify what you want to do.

(also if you haven’t already read it or heard about it I can recommend W. S. Vincent’s book “Django for API’s”, I’m working my way through it right now)

The easiest way would be if you define the depth under class Meta. ( Remember the serializer will only work for the get methods. )

Thanks


social media digital marketing dombivali new project