15

I'm calling a simple get API using djangorestframework. My Model is

class Category(models.Model):
    category_id = models.AutoField(primary_key=True)
    category_name = models.CharField("Category Name", max_length = 30)
    category_created_date = models.DateField(auto_now = True, auto_now_add=False)
    category_updated_date = models.DateField(auto_now = True, auto_now_add=False)

    def __str__(self):
        return self.category_name

serializer.py

class CategorySerializer(serializers.ModelSerializer) :
    class Meta:
        model = Category
        fields = ['category_id', 'category_name']

def category_list(request):
    if request.method == 'GET':
        categories = Category.objects.all()
        serializer = CategorySerializer(categories, many=True)
        return Response(serializer.data)

It's working fine when i hit request on the URL and returning following response.

[
    {
        "category_id": 1,
        "category_name": "ABC"
    }
]

i want to change the response field names as it's for my DB only and don't want to disclose in response. If i change the name in serializer class than it's giving no field match error.

Also i want to customise other params like above response in response object with message and status like below.

{
status : 200,
message : "Category List",
response : [
        {
            "id": 1,
            "name": "ABC"
        }
    ]
}

Need a proper guide and flow. Experts help.

Pinank Lakhani
  • 1,109
  • 2
  • 11
  • 31
  • check this https://stackoverflow.com/questions/22958058/how-to-change-field-name-in-django-rest-framework – Windsooon Sep 05 '16 at 06:10

4 Answers4

41

First of all using category_ in field names is redundant. Because you are already assigning this fields to Category model, and by doing this you are creating "namespace" for this fields.

class Category(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField("Category Name", max_length = 30)
    created_date = models.DateField(auto_now = True, auto_now_add=False)
    updated_date = models.DateField(auto_now = True, auto_now_add=False)

    def __str__(self):
        return self.name

Second In django id AutoField is created automatically why would you need set it explicitly?

And answering your question There is source parameter in serializer fields.

class CategorySerializer(serializers.ModelSerializer):
    renamed_id = serializers.IntegerField(source='category_id')
    renamed_name = serializers.CharField(source='category_name')

    class Meta:
        model = Category
        fields = ['renamed_id', 'renamed_name']

And than you can change your response manually

from rest_framework import status

def category_list(request):
    if request.method == 'GET':
        categories = Category.objects.all()
        serializer = CategorySerializer(categories, many=True)
        response = {
            'status': status.HTTP_200_OK,
            'message' : "Category List",
            'response' : serializer.data
        }
        return Response(response)
Sardorbek Imomaliev
  • 14,861
  • 2
  • 51
  • 63
  • Tried but its giving AssertionError : The field 'renamed_id' was declared on serializer CategorySerializer, but has not been included in the 'fields' option. – Pinank Lakhani Sep 05 '16 at 06:56
  • You need to just change `fields` parameter in `Meta`. See updated answer. – Sardorbek Imomaliev Sep 05 '16 at 06:59
  • Working. Thank you. Can you let me know which is the best practice to write customising response code. I mean to write in serializers.py or views.py? – Pinank Lakhani Sep 05 '16 at 07:02
  • It depends on what you are trying to achieve. The best way would be write Class Based View which than can subclassed for reuse. – Sardorbek Imomaliev Sep 05 '16 at 07:09
  • It's working for get request but when i run a curl request for PUT it fails curl -X PUT localhost:8000/api/add-category/4 -d "category_name=xyz" It works fine for PUT when i don't rename the fields – Pinank Lakhani Sep 05 '16 at 10:09
  • @PinankLakhani you need to write custom `create` and `update` methods on your serializer. http://www.django-rest-framework.org/api-guide/serializers/#saving-instances where you would put data into real fields. `instance.category_name = validated_data.get('renamed_name', instance.category_name)` – Sardorbek Imomaliev Sep 05 '16 at 10:13
2

You can override to_representation function in serializer.Check the following code you can update data dictionary as you want.

class CategorySerializer(serializers.ModelSerializer) :
    class Meta:
        model = Category
        fields = ['category_id', 'category_name']
    def to_representation(self, instance):
        data = super(CategorySerializer, self).to_representation(instance)
        result_data={"status" : 200,"message" : "Category List"}
        result_data["response"]=data
        return result_data
Himanshu dua
  • 2,496
  • 1
  • 20
  • 27
  • It's adding in each object [ { "status": 200, "message": "Category List", "response": { "category_id": 1, "category_name": "Educational News" } }, { "status": 200, "message": "Category List", "response": { "category_id": 2, "category_name": "Death News" } }, ] – Pinank Lakhani Sep 05 '16 at 06:47
2

You can just wrap it up in json. This is the way you render the way you want:

from django.http import HttpResponse
import json

def category_list(request):
    if request.method == 'GET':
        categories = Category.objects.all()
        serializer = CategorySerializer(categories, many=True)
        response = {'code: 200, 'message': 'Category List', 'response': serializer.data}
        return HttpResponse(json.dumps(response), mimetype='application/json')

This is the way you can rename your fields:

class CategorySerializer(serializers.ModelSerializer):
    name = serializers.CharField(source='category_name')

    class Meta:
        model = Category
        fields = ['category_id', 'name']

This is the docs for serializing with different names.

vishes_shell
  • 22,409
  • 6
  • 71
  • 81
  • Now it's giving me following error File "/Users/smartSense/Pinank/Django/Work/MadhaparDemo/MadhaparDemo/ Category/urls.py", line 3, in from .views import category_list File "/Users/smartSense/Pinank/Django/Work/MadhaparDemo/MadhaparDemo/ Category/views.py", line 15 response = {'code: 200, 'message': 'Category List', response: serializer.data} – Pinank Lakhani Sep 05 '16 at 06:25
  • @PinankLakhani i am sorry, i changed that line a bit, try it – vishes_shell Sep 05 '16 at 06:26
  • Working But still i can't import simplejson. Also i want to rename the field names too – Pinank Lakhani Sep 05 '16 at 06:32
  • @PinankLakhani you do this with `json` package(updated answer). What do you mean by renaming fields? You can do this in serializer – vishes_shell Sep 05 '16 at 06:34
  • Tried but its giving AssertionError : The field 'name' was declared on serializer CategorySerializer, but has not been included in the 'fields' option. – Pinank Lakhani Sep 05 '16 at 06:54
  • Working. Thank you. Can you let me know which is the best practice to write customising response code. I mean to write in serializers.py or views.py? – Pinank Lakhani Sep 05 '16 at 07:02
  • @PinankLakhani it's really depends, because what are you trying to achive? Is it like HTTP response code or what? I believe it's not the best way to pass code in json object, you need to put that code in HTTP header – vishes_shell Sep 05 '16 at 07:06
  • It's working for get request but when i run a curl request for PUT it fails curl -X PUT http://localhost:8000/api/add-category/4/ -d "category_name=xyz" It works fine for PUT when i don't rename the fields – Pinank Lakhani Sep 05 '16 at 10:08
1

In Django 2.1.1 if you are using a viewset, you can customize the other parts of your response by overriding the .list() action like this

from rest_framework import status
from django.http import HttpResponse
import json

class CategoryViewset(viewsets.ReadOnlyModelViewSet):
    categories = Category.objects.all()

    def list(self, request):
        if request.method == 'GET':
            serializer = CategorySerializer(self.categories, many=True)
            response = {
                'status': status.HTTP_200_OK,
                'message' : "Category List",
                'response' : serializer.data,
            }
            return HttpResponse(json.dumps(response), content_type='application/json')
Jimmu
  • 11
  • 1