4

Given below is my serializer class. I have all fields in one model.I would like to change the representation of serializer data in custom format. Tried to_representation method of serializer but could not success.

class MyListSerilizer(ModelSerializer):
  class Meta:
    model=MyModel
    fields=['Name','Address_ID','Portal','Address','City','DisplayOrderDateTime','Email','Order_ID','Order_Code','Item_Code','DispatchedOn','Payment_Mode','Shipping_Charge','ShippingMethodCode','ShippingMethodCharges','CashOnDeliveryCharges','CurrencyCode','BillingAddress','GiftWrapCharges','SaleOrderItemCode','Shipping_ref','Cancellable','OnHold','Quantity','Invoice_No''Portal',........]

So in my view class defined and output corresponding to them also mentioned over here.

   class MyListAPIView(ListAPIView):
      def list(self,request):
          queryset=MyModel.objects.all()
          serializer=MyListSerilizer(queryset,many=True)
          return Response({'Records':serializer.data})

Output :---------->Corresponding to view is

  "Records": [
    {
        "Name": "abc",
        "Address_ID": "6819319",
        "Portal": "amksl",
        "Address": "",
        "City": "absjsls",
        "DisplayOrderDateTime": null,
        "Email": "[email protected]",
        "Order_ID": "",
        "Order_Code": "",
        "Item_Code": "",
        "DispatchedOn": "",
        "Payment_Mode": ""
     },
      {
         "Name": "abc",
        "Address_ID": "6819319",
        "Portal": "amksl",
        "Address": "",
        "City": "absjsls",
        "DisplayOrderDateTime": null,
        "Email": "[email protected]",
        "Order_ID": "",
        "Order_Code": "",
        "Item_Code": "",
        "DispatchedOn": "",
        "Payment_Mode": ""
     },
      so on....

so my question is how would i achieve this json format. In short how do i customize my view class

     {
      "identifiers":{
                "email":"[email protected]",
                "phone":"123664"
              },
"activity_type": "purchase",
"timestamp": "UNIX TIMESTAMP",                
"products": [{
                "brandName": "abc",
                "id": "1",                                  
                "sku": "abcd",                                
                "name": "mnis",                           
                "price": 12.9,
                "discount": "",
                "quantity": "",
                "currency": ""
                 }]
"cart_info":{
                "total":"",
                "revenue":"",
                "currency":""
            },
"Order_info":{
               "total":"2121",
                .
                .
                .
             }
  },
   {
      "identifiers":{
                "email":"[email protected]",
                "phone":"123664"
              },
"activity_type": "purchase",
"timestamp": "UNIX TIMESTAMP",                
"products": [{
                "brandName": "abc",
                "id": "1",                                  
                "sku": "abcd",                                
                "name": "mnis",                           
                "price": 12.9,
                "discount": "",
                "quantity": "",
                "currency": ""
                 }]
"cart_info":{
                "total":"",
                "revenue":"",...so on
3
  • 1
    you rather have to customize your MyListSerilizer class. read docs about serializers -> django-rest-framework.org/api-guide/serializers , should help Commented Jul 29, 2017 at 12:38
  • how would i customize MyListSerializer for single model , i tried breaking up of fields into different serializer classes but not workable, if you provide me small example it would be best for me Commented Jul 29, 2017 at 12:54
  • you can add some custom fields using SerializerMethodField -> django-rest-framework.org/api-guide/fields/… Commented Jul 29, 2017 at 13:17

3 Answers 3

6

override to_representation method in the serializer class

class MyListSerilizer(ModelSerializer):

     class Meta:
        model=MyModel
        fields=['Name','Address_ID','Portal','Address','City','DisplayOrderDateTime','Email','Order_ID','Order_Code','Item_Code','DispatchedOn','Payment_Mode','Shipping_Charge','ShippingMethodCode','ShippingMethodCharges','CashOnDeliveryCharges','CurrencyCode','BillingAddress','GiftWrapCharges','SaleOrderItemCode','Shipping_ref','Cancellable','OnHold','Quantity','Invoice_No''Portal',........]


     def to_representation(self, instance):
         # instance is the model object. create the custom json format by accessing instance attributes normaly and return it


        identifiers = dict()
        identifiers['email'] = instance.Email
        identifiers['phone'] = instance.phone

        representation = {
            'identifiers': identifiers,
            'activity_type': instance.xxxx,
            'timestamp': instance.xxxxx,
            .
            .
            .  -> your custom data
         } 

     return representation

whenever you call serializer.data, this representation dictionary will be returned

Sign up to request clarification or add additional context in comments.

Comments

1

There is the method called to_representation in DRF. Reference:http://www.django-rest-framework.org/api-guide/fields/

Comments

0

Create a file renderers.py anywhere in the project and write the following code:

from bson import ObjectId
from rest_framework import status
from rest_framework.renderers import JSONRenderer
from rest_framework.utils import encoders


def get_status(code):
    """Get the human readable SNAKE_CASE version of a status code."""
    for name, val in status.__dict__.items():
        if not callable(val) and code is val:
            return name.replace("HTTP_%s_" % code, "")
    return "UNKNOWN"


class BaseAPIJSONRenderer(JSONRenderer):
    def render(self, data, accepted_media_type=None, renderer_context=None):
        """
        Custom API response format for all APIs
        Example success:
        {
            "code": 200,
            "status": "OK",
            "data": {
                "key": "value"
            }
        }

        Example error:
        {
            "code": 404,
            "status": "NOT_FOUND",
            "errors": [
                {
                    "detail": "Not found."
                }
            ]
        }
        """
        response = renderer_context["response"]

        # Modify the response into a cohesive response format
        modified_data = {}
        modified_data["code"] = response.status_code
        modified_data["status"] = get_status(response.status_code)
        if status.is_client_error(response.status_code) or status.is_server_error(
            response.status_code
        ):
            modified_data["errors"] = data
        else:
            modified_data["data"] = data

        return super().render(modified_data, accepted_media_type, renderer_context)

class MyJSONEncoder(encoders.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, ObjectId):
            return str(obj)
        return encoders.JSONEncoder.default(self, obj)

def get_error_message(error_dict):
    response = error_dict[next(iter(error_dict))]
    error_name = next(iter(error_dict))
    if isinstance(response, dict):
        response = get_error_message(response)
    elif isinstance(response, list):
        response_message = response[0]
        if isinstance(response_message, dict):
            response = get_error_message(response_message)
        else:
            response = response[0]

    return response.replace("This", error_name)
class MyJSONRenderer(JSONRenderer):
    encoder_class = MyJSONEncoder

    def render(self, data, accepted_media_type=None, renderer_context=None):
        """
        Modify API response format.
        Example success:
        {
            "code": 200,
            "status": "OK",
            "message": "updated succesfully",
            "data": {
                "name": "name"
            }
        }

        Example error:
        {
            "code": 404,
            "status": "NOT_FOUND",
            "message": "Not Found"
        }
        """
        response = renderer_context["response"]

        # Modify the response into a cohesive response format
        modified_data = {}
        modified_data["code"] = response.status_code
        modified_data["status"] = get_status(response.status_code)

        if status.is_client_error(response.status_code) or status.is_server_error(
            response.status_code
        ):
            if isinstance(data, list) and data:
                if isinstance(data[0], dict):
                    message = (get_error_message(data),)
                elif isinstance(data[0], str):
                    message = data[0]
            if isinstance(data, dict):
                message = get_error_message(data)
            modified_data["message"] = message
        else:
            if isinstance(data, dict):
                message = data.pop("message_", None)
                if message:
                    modified_data["message"] = message
                if data.get("results") is not None:

                    modified_data["count"] = data.get("count")
                    modified_data["next"] = data.get("next")
                    modified_data["previous"] = data.get("previous")
                    modified_data["data"] = data.get("results")
                    # if data.get("page"):
                    #     modified_data["page"] = data.get("page")
                    # else:
                    #     modified_data["last_id"] = data.get("last_id")
                    # modified_data["last_page"] = data.get("last_page")
                else:
                    modified_data["data"] = data
            else:
                modified_data["data"] = data
        

        return super().render(modified_data, accepted_media_type, renderer_context)

After creating the file defined in a setting like this:

"DEFAULT_RENDERER_CLASSES": [
        "app_modules.apis.base.renderers.MyJSONRenderer",
    ],

app_modules.apis.base its a file path

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.