0

I'm trying to create objects just by getting a json that have the objects nested in it,for example, I have a model with only one field that is name and im getting this json

{"name":"category1",
"children":[{
   "name":"category1.1",
   "children":[]},
   {"name":"category1.2",
   "children":[{"name":"category1.2.1",
                "children":[]}]
}
]
}

What i'm trying to achieve is to read this,and create category objects that reference its parent or its children, I've tried multiple solutions inspired from these answers but I can't seem to get close to getting the job done(Django rest framework nested self-referential objects -- How to create multiple objects (related) with one request in DRF?)


I've tried having the model with only name and a foreign key that reference the category itself,and I added recursive field to my serializer like this:

class RecursiveField(serializers.Serializer):
    def to_representation(self, value):
        serializer = self.parent.parent.__class__(value, context=self.context)
        return serializer.data
class CategorySerializer(serializers.ModelSerializer):
subcategories = RecursiveField(many=True,allow_null=True)

class Meta:
    model = Category
    fields = ['name','subcategories']
def create(self, validated_data):
    category = None
    if len(validated_data['subcategories'])==0:
        category = Category.objects.create(name=validated_data['name'])
    else:
        for i in range(len(validated_data['subcategories'])):
            child = validated_data['subcategories']
            child_list = list(child.items())
            subcat = child_list[1]
            if len(subcat)==0:
                subcategory = Category.objects.create(name=child.get('name'))
            category = Category.objects.create(name=validated_data['name'],children=subcategory)
    return category

The best I got with this solution is being able to create the parent object,but I wasn't able to get the children objects instead I got an empty OrderedDict() (I only tried this solution to see if i can access the children but apparently i can't,I get an empty OrderedDict() in child variable)

Am I looking at this from the wrong prespective? or is my model architecture not suitable for this? if not,what am i doing wrong

B Z Ilyes
  • 28
  • 4

1 Answers1

0

I think I found a solution that solves all the problems in my case,It's not the most optimized and if someone can share a better one I'm happy to check it out,but here is:

I went for thick view instead of a thick serializer,I kept the model as it is with 2 fields,name field and foreign key that references the parent,as for the serializer:

class CategorySerializer(serializers.Serializer):
    name = serializers.CharField()
    children = serializers.ListField()

I still have to add validators for the list field,as for the view I went for a recursive function that goes through all the children and adds them:

def post(self,request):
    serializer = self.get_serializer(data=request.data)
    serializer.is_valid(raise_exception=True)
    parent = serializer
    #creating the parent object
    category = Category.objects.create(name=parent.validated_data['name'])
    #saving the parent object's id
    parent_id = category.id
    #Checking if the item has children
    children = parent.validated_data['children']
    #if the parent doesn't have children nothing will happen
    if children == None:
        pass
    #Call the recursion algorithm to create all the children
    else:
        self.recursion_creation(children,parent_id)

    return Response({
        "id":parent_id,
    })

def recursion_creation(self,listOfChildren,parentId):
    #This will go through all the children of the parent and create them,and create their children
    for k in range(len(listOfChildren)):
        name = listOfChildren[k].get("name")
        #create the child
        category = Category.objects.create(name=name,parent_id=parentId)
        categoryId = category.id
        #save it's id
        children = listOfChildren[k].get("children")
        #if this child doesn't have children the recursion will stop
        if children==None:
            pass
        #else it will apply the same algorithm and goes through it's children and create them and check their children
        else:
            self.recursion_creation(children,categoryId)

I'm looking forward to any improvements or other answers that solve the problem.

B Z Ilyes
  • 28
  • 4