djangocurldjango-rest-frameworkdjango-rest-viewsetsdjango-rest-framework-jwt

django rest framework serializer saving field value as empty strings, but no errors


django rest framework serializer saving field value as empty strings, but no errors

views.py

from django.shortcuts import render
from rest_framework import viewsets

from rest_framework.authentication import TokenAuthentication

from .models import MyTodo
from .serializers import  MyTodoSerializer


class MyTodoView(viewsets.ModelViewSet):

    queryset = MyTodo.objects.all()
    serializer_class = MyTodoSerializer

and my model is

models.py

from django.db import models

# Create your models here.

class MyTodo(models.Model):
    # Autoincrement id
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=200, blank=True, default='')
    description = models.CharField(max_length=20, blank=True, default='')
    created_on = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title

and my serializer is

serializers.py

from rest_framework import serializers
from mytodo.models import MyTodo

class MyTodoSerializer( serializers.ModelSerializer ):

    title = serializers.CharField(max_length=200, default='')
    description = serializers.CharField(max_length=200, default='')
    created_on = serializers.DateTimeField(format="%Y-%m-%dT%H:%M:%S", required=False)

    def create(self, validated_data):
        return MyTodo.objects.create(**validated_data)

    def update(self, instance, validated_data):
        instance.title = validated_data.get('title', instance.title)
        instance.description = validated_data.get('description', instance.description)
        instance.created_on = validated_data.get('created_on', instance.created_on )
        instance.save()
        return instance


    class Meta:
        model = MyTodo
        fields = [ 'id','url','title','description', 'created_on' ]

Looks pretty simple, straight forward but by CURL calls are saving empty fields, but Browsable API View is working very fine. Please tell me what am I doing wrong.

Here is what I am trying to do

Curl Client

#!/bin/bash

b64credential=$(echo 'admin:admin' | base64)

access_token=$(curl -d "username=admin&password=admin"  -X POST 'http://localhost:8000/api/token/' \
-H 'Accept:application/json' \
-H "Authorization:Basic  ${b64credential}" | jq --raw-output '.access' )

echo "Access token : $access_token"

# post a todo to  mytodo api

curl -vvv -L -d '{"title": "Awesome things to be done" ,"description": "Really great things stay alert"}' \
     -X POST 'http://localhost:8000/mytodo/' \
     -H 'Accept:application/json' \
     -H "Authorization:Bearer  ${access_token}"

the response looks like this

{"id":23,"url":"http://localhost:8000/mytodo/23/","title":"","description":"","created_on":"2021-05-14T10:02:45"}

Here are couple more questions

  1. Why I get title:"", description: "",

  2. in the view, I have only serializer_class = MyTodoSerializer have no information about actual request processing, how Django is correctly calling the right method MyTodoSerializer.create()


Solution

  • You have set '' as default value and cURL payload is not passed to Django.

    The reason is your header is wrong.

    Is

         -H 'Accept:application/json' \
    

    should be

         -H "Content-Type: application/json"
    

    Try this instead.

    curl -vvv -L -d '{"title": "Awesome things to be done" ,"description": "Really great things stay alert"}' -X POST 'http://localhost:8000/mytodo/' -H "Content-Type: application/json" -H "Authorization:Bearer  ${access_token}"
    

    The difference between these two headers can be found here.