Nikhil Sardana
Nikhil Sardana

Reputation: 365

Json serialized data having backslashes

I am using rest_framework.response method to send objects of multiple django models. However, the response containts backslashes with quotes. Here is my view:

@api_view()
def myfunctions(request,id):
    responseData = {}
    userObject = TifUser.objects.filter(id=id)
    attendances = Attendance.objects.filter(User=userObject)
    leaves = Leave.objects.filter(User=userObject)
    odds = ODD.objects.filter(User=userObject)
    printjobs = PrintJob.objects.filter(User=userObject)
    issues = Issue.objects.filter(User=userObject)

    #serialize into json
    userObject = serializers.serialize("json", userObject)
    attendances = serializers.serialize("json",attendances)
    leaves = serializers.serialize("json",leaves)
    odds = serializers.serialize("json",odds)
    printjobs = serializers.serialize("json",printjobs)
    issues = serializers.serialize("json",issues)

    #set responseData dictionary values
    responseData['user'] = userObject
    responseData['attendances'] = attendances
    responseData['leaves'] = leaves
    responseData['odds'] = odds
    responseData['printjobs'] = printjobs
    responseData['issues'] = issues
    #responseData['attendances'] = userObject
    return response.Response(responseData)

The json response I am getting is:

{"attendances":"[{\"model\": \"mainApp.attendance\", \"pk\": 5, \"fields\": {\"ArrivalTime\": \"2016-06-27T18:45:46.355Z\", \"DepartureTime\": null, \"User\": 4, \"ArrivalImei\": \"1\", \"DepartureImei\": null, \"Hash\": \"321f059c-4230-417a-adff-f0035097c85d\"}}, {\"model\": \"mainApp.attendance\", \"pk\": 13, \"fields\": {\"ArrivalTime\": \"2016-07-18T15:40:39.943Z\", \"DepartureTime\": null, \"User\": 4, \"ArrivalImei\": \"2\", \"DepartureImei\": null, \"Hash\": \"e61fad3e-8238-46fc-b09b-8b7754d43f3b\"}}]","printjobs":"[{\"model\": \"mainApp.printjob\", \"pk\": 1, \"fields\": {\"User\": 4, \"DateAdded\": \"2016-07-18\", \"Status\": \"disapproved\", \"Person\": 5, \"Level\": \"boss\", \"Client\": \"someone\", \"HandledBy\": \"tester\", \"SanctionedBy\": \"myself\", \"AdvancePayment\": 0, \"FinalPayment\": 1000, \"PaymentNumber\": 1, \"Remarks\": \"something\"}}]","odds":"[]","user":"[{\"model\": \"mainApp.tifuser\", \"pk\": 4, \"fields\": {\"AuthUser\": 7, \"Head\": null, \"Boss\": null, \"ClrLevel\": 1, \"Department\": 1, \"DesignationName\": 1, \"Name\": \"tester\", \"IsRegistered\": true, \"DateOfBirth\": \"1222-11-11\", \"Anniversary\": \"2001-12-22\", \"Mobile\": \"2134567890\", \"gcmDevice\": null, \"FatherName\": \"\", \"MotherName\": \"\", \"PersonalEmail\": \"\", \"Gender\": \"Male\", \"CurrentAddress\": \"\", \"PermanentAddress\": \"\", \"PANNumber\": \"\", \"AadharCardNumber\": null, \"BloodGroup\": \"\", \"MaritalStatus\": \"Married\", \"ProfilePhoto\": \"\", \"Imei\": \"\"}}]","leaves":"[]","issues":"[]"}

Is there any other way to do it? What I understand is, it is encoding the data twice (once in serializers.serialize and then in response.Response). But I dont want that. I want nested objects. Something like this:

{"attendances":[{"model": "mainApp.attendance", "pk": 5, "fields": {"ArrivalTime": "2016-06-27T18:45:46.355Z", "DepartureTime": null, "User": 4, "ArrivalImei": "1",...

Can anyone tell me how to achieve this? Thanks in advance.

Upvotes: 8

Views: 4756

Answers (2)

Anentropic
Anentropic

Reputation: 33923

As you identified, you are double-serializing everything by converting your querysets to JSON strings, adding them to a dict and then passing the dict to response.Response.

Much of the point of using Django REST Framework is that is handles the serialization for you, so the goal should be to avoid serializing to JSON strings yourself in the api view.

To make best use of DRF you need to define a ModelSerializer for each of the models you want to return in the response.

One thing that is confusing in DRF is the terminology. Normally when we talk about "serialization" it means converting objects to a string (i.e. JSON). But in DRF, serializers actually convert complex objects -> primitive objects. So when you use a ModelSerializer to "serialize" your queryset it does not produce a JSON string, but rather primitive python objects (a dict) that can then be serialized, in the conventional sense, to a JSON string without errors. This 'real' serialization is done for you by the Response class.

So I suggest as a starting point:

class TifUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = TifUser


class AttendanceSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Attendance


class LeaveSerializer(serializers.ModelSerializer):
    class Meta:
        model = Leave


class ODDSerializer(serializers.ModelSerializer):
    class Meta:
        model = ODD


class PrintJobSerializer(serializers.ModelSerializer):
    class Meta:
        model = PrintJob

class IssueSerializer(serializers.ModelSerializer):
    class Meta:
        model = Issue


@api_view()
def myfunctions(request, id):
    users = TifUser.objects.filter(id=id)
    user_serializer = TifUserSerializer(users, many=True)

    attendances = Attendance.objects.filter(User=userObject)
    attendance_serializer = AttendanceSerializer(attendancesv, context={'request': request})

    leaves = Leave.objects.filter(User=userObject)
    leave_serializer = LeaveSerializer(leaves, many=True)

    odds = ODD.objects.filter(User=userObject)
    odd_serializer = ODDSerializer(odds, many=True)

    printjobs = PrintJob.objects.filter(User=userObject)
    printjob_serializer = PrintJobSerializer(printjobs, many=True)

    issues = Issue.objects.filter(User=userObject)
    issue_serializer = IssueSerializer(issues, many=True)

    responseData = {}
    responseData['user'] = user_serializer.data
    responseData['attendances'] = attendance_serializer.data
    responseData['leaves'] = leave_serializer.data
    responseData['odds'] = odd_serializer.data
    responseData['printjobs'] = printjob_serializer.data
    responseData['issues'] = issue_serializer.data

    return response.Response(responseData)

Upvotes: 4

Nikhil Sardana
Nikhil Sardana

Reputation: 365

I finally managed to solve it. The problem was, when the objects were serialized using serializer.serialize() function, I was getting a string. Whereas I wanted a dict. I had to use json.loads() to convert the string into a dictionary as:

responseData['user'] = json.loads(userObject)

And everything worked as I wanted to. Now, the response is something like:

{
    "attendances": [
        {
            "pk": 5,
            "model": "mainApp.attendance",
            "fields": {
                "DepartureTime": null,
                "Hash": "321f059c-4230-417a-adff-f0035097c85d",
                "ArrivalImei": "1",
                "DepartureImei": null,
                "User": 4,
                "ArrivalTime": "2016-06-27T18:45:46.355Z"
            }
        },

Upvotes: 4

Related Questions