Home > OS >  Post request with an object via serializer many=False
Post request with an object via serializer many=False

Time:12-03

I am trying to make a POST request with an object for example this is how I send my request :

{
    "title": "Haloween",
    "body": " This is one of the greatest ones",
    "grade_level": {
        "id": 2,
         "country": "UG"
    },
    "tags": [{"name": "Jamming"}]
}

So I wanted to post an object :

"grade_level": {
            "id": 2,
             "country": "UG"
        }

and below is my Serializer I use :

class GradeClassSerializer(CountryFieldMixin, serializers.ModelSerializer):
    """GradeClass Serializer."""

    class Meta:
        model = ClassGrade
        fields = ('id', 'grade', 'country', 'color_code', )

class PostSerializer(serializers.ModelSerializer):
    """Post Serializer"""
    owner = UserProfile(read_only=True)
    tags = TagSerializer(many=True)
    comments = CommentSerializer(many=True, read_only=True)
    slug = serializers.SlugField(read_only=True)
    grade_level = GradeClassSerializer(many=False)

When I send the object grade_level , I cant seem to receive it it only receives the the id :

def create(self, validated_data):
        """Create a blog post in a customized way."""

        grade_level = validated_data.pop('grade_level', {})
        status = validated_data.pop('status', '')
        post = Post.objects.create(**validated_data,
                                   owner=self.context['request'].user)

        if grade_level:
            grade = ClassGrade.objects.get(id=grade_level['id'])
            post.grade_level = grade
            post.save()

        return post

When I make a request, this is what happens :

KeyError: 'id'

The object comes with only an country without an id.

This is what grade_level = validated_data.pop('grade_level', {}) prints :

OrderedDict([('country', 'UG')])

How can get the id from the object.

NOTE:

  • id is not flagged as read_only

EDIT : In the views.py below is the view :

class PostList(generics.ListCreateAPIView):
    """Blog post lists"""
    queryset = Post.objects.filter(status=APPROVED)
    serializer_class = serializers.PostSerializer
    authentication_classes = (JWTAuthentication,)
    permission_classes = (PostsProtectOrReadOnly, IsMentorOnly)
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]

  

    def post(self, request, *args, **kwargs):
        serializer = self.serializer_class(data=request.data, context={
            'request': request})
        if serializer.is_valid():
            serializer.save()
            return response.Response(serializer.data,
                                     status=status.HTTP_201_CREATED, )
        return response.Response(serializer.errors,
                                 status=status.HTTP_400_BAD_REQUEST)

Then models :

class ClassGrade(TimeStampedModel, models.Model):
    """ClassGrade is the class which Identifies the class or grade."""
    grade = models.CharField(
        _('Name'), max_length=150, null=True, blank=True)
    country = CountryField()
    color_code = ColorField(format='hexa', default='#33AFFF', null=True)

    def __str__(self):
        return self.grade

class Post(MainProcess, TimeStampedModel, models.Model):
    """Post model."""
    title = models.CharField(_('Title'), max_length=100, blank=False,
                             null=False)
    image = models.ImageField(_('Image'), upload_to='blog_images', null=True,
                              max_length=900)
    body = models.TextField(_('Body'), blank=False)
    description = models.CharField(_('Description'), max_length=400,
                                   blank=True, null=True)

CodePudding user response:

By default, DRF treats the id(PrimaryKey) inside ModelSerializer as read-only. So to override this behavior u can try PrimaryKeyRelatedField

class GradeClassSerializer(CountryFieldMixin, serializers.ModelSerializer):
    """GradeClass Serializer."""

    id = serializers.PrimaryKeyRelatedField(queryset=ClassGrade.objects.all(), 
        required=True)
    class Meta:
        model = ClassGrade
        fields = ('id', 'grade', 'country', 'color_code', )

CodePudding user response:

So, by default, DRF will use the model fields in a ModelSerializer if you don’t define a field. Because the Id is an auto-created primary key (Django does this if you don’t explicitly override it) and Django assumes a primary key is read only, the id is omitted from the deserialized request

  • Related