djongo icon indicating copy to clipboard operation
djongo copied to clipboard

nested document is not serialized in json format

Open RamazanDemirci opened this issue 4 years ago • 6 comments

i try store nested json document in mongodb. insert is ok but when i get document nested object not json format but string

i want to store json files in mogodb and create and get with django rest framework.

i share my code below. this code insert posted data into mongo. but when i 'get' data, nested object represent as string. i want to get object as json.

i reseached a lot but i haven't found anything about this.

postman get result :

{ "id": 1, "country": "United Kingdom", "country_code": "UK", "nested": "{"name": "London", "icon": "icon_url"}" #problem here. this field must be json object. in mogodb json object here }

Python script


###########################models.py########################

from djongo import models

class Nest(models.Model):
    name = models.CharField(max_length=150, blank=True, null=True)
    icon = models.CharField(max_length=150, blank=True, null=True)

    class Meta:
        abstract = True

class Root(models.Model):
    #_id = models.ObjectIdField()
    country = models.CharField(max_length=200, blank=True, null=True)
    country_code = models.CharField(max_length=5, blank=True, null=True)
    nested = models.EmbeddedField(
        model_container=Nest, null=True)
		
###########################serializers.py#####################
from rest_framework import serializers
from .models import Root

class RootSerializer(serializers.ModelSerializer):

    class Meta:
        model = Root
        fields = '__all__'
		
###########################views.py###########################
from django.shortcuts import render

from django.http.response import JsonResponse
from rest_framework.parsers import JSONParser
from rest_framework import status

from .models Root
from .serializers import RootSerializer
from rest_framework.decorators import api_view

@api_view(['GET', 'POST', 'DELETE'])
def root(request):
    if request.method == 'GET':
        first_root = Root.objects.first()
        root_serializer = RootSerializer(first_root, many=False)
        return JsonResponse(root_serializer.data, safe=False)
    elif request.method == 'POST':
        root_data = JSONParser().parse(request)
        root_serializer = RootSerializer(data=root_data)
        if root_serializer.is_valid():
            root_serializer.save()
            return JsonResponse(root_serializer.data, status=status.HTTP_201_CREATED)
        return JsonResponse(root_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

###########################urls.py###########################
from django.conf.urls import url
from rootApp import views

urlpatterns = [
    url(r'^api/root$', views.root),
]

###########################settings.py#######################
DATABASES = {
    'default': {
        'ENGINE': 'djongo',
        'NAME': 'root_db',
        'HOST': '127.0.0.1',
        'PORT': 27017,
    }
}


RamazanDemirci avatar Aug 17 '20 08:08 RamazanDemirci

i have the same issue, someone help plz....

yuri-potatoq avatar Mar 16 '21 22:03 yuri-potatoq

Following the question. I have the exact same issue.

adlzanchetta avatar May 09 '21 16:05 adlzanchetta

Did you try to implement a serializer for the embedded field Nest? Then, you need to apply it on the root serializer - otherwise rest_framework just serializes the fields that contain objects as string (its the default behaviour, not a djongo issue).

https://www.django-rest-framework.org/api-guide/relations/#nested-relationships

class RootSerializer(serializers.ModelSerializer):
    nested = NestSerializer(Nest)

    class Meta:
        model = Root
        fields = '__all__'

SebastianRemander avatar May 11 '21 05:05 SebastianRemander

@SebastianRemander Thank for the suggestion. Your solution probably works when both Root and Nest are non-abstract classes. It does not work in our case because here the class Nest is abstract. When we try it, we get the following error:

ValueError: Cannot use ModelSerializer with Abstract Models.

In my particular case, I am setting Nest as and abstract class just because Nest defines a structured dictionary attribute of Root, thus it should not have an id.

May it be just a poor design choice?

adlzanchetta avatar May 11 '21 12:05 adlzanchetta

I see, that is unfortunate and definitely djongo issue after all. I don't know if it's a design choice or can they actually fix that, since the django-rest-framework does not seem to support these kind of embedded models...

I'm no djongo expert, but you could try switching to mongoengine and define all your "data" models with it, and only use djongo for the internal django stuff. At least that's how I've done it, and it works to some extent quite neatly.

SebastianRemander avatar May 12 '21 05:05 SebastianRemander

I totaly forgot this post. i had handled this issue by myself. my solution is in the following link see: https://stackoverflow.com/questions/63446810/django-nested-document-serializer-problem/63592038#63592038

i created simply global variable and if i have to makemigrate this variable set to True and create migration files then i return this variable to False for runtime serialization. this is not neat solution but it works for me.

this variable determine if nested classes is meta class or not.

from djongo import models

isMigrate = False       //added this line

class Nest(models.Model):
    name = models.CharField(max_length=150, blank=True, null=True)
    icon = models.CharField(max_length=150, blank=True, null=True)

class Meta:
    abstract = isMigrate        //changed this line. 

class Root(models.Model):
    #_id = models.ObjectIdField()
    country = models.CharField(max_length=200, blank=True, null=True)
    country_code = models.CharField(max_length=5, blank=True, null=True)
    nested = models.EmbeddedField(
        model_container=Nest, null=True)
    

###########################serializers.py##################### from rest_framework import serializers from .models import Root

class NestSerializer(serializers.ModelSerializer):              # added
    class Meta:                                                 # this
        model = Nest                                            #
        fields = '__all__'                                      # lines

class RootSerializer(serializers.ModelSerializer):

    class Meta:
        model = Root
        fields = '__all__'

RamazanDemirci avatar Feb 03 '22 19:02 RamazanDemirci