1

I'm trying to create nested objects in Django Rest Framework according to the docs.

this my models.py :

from django.db import models


class Request(models.Model):
    origin = models.CharField(max_length=255, blank=True)

    def __str__(self):
        return str(self.id)


class RequestOrders(models.Model):
    request_id = models.ForeignKey(Request, related_name='request_orders', on_delete=models.DO_NOTHING, blank=True, null=True)
    position = models.CharField(max_length=255, blank=True)
    destination = models.CharField(max_length=255, blank=True)
    order_ref = models.CharField(max_length=255, blank=True)

    def __str__(self):
        return self.id


class RequestOrderItemss(models.Model):
    request_order_id = models.ForeignKey(RequestOrders, related_name='request_order_itemss', on_delete=models.DO_NOTHING, blank=True, null=True)
    product_id = models.ForeignKey('product.Product', on_delete=models.DO_NOTHING, blank=True, null=True)
    qty = models.CharField(max_length=255, blank=True)

    def __str__(self):
        return self.id

Here's my serializers.py :

from rest_framework import serializers
from request.models import Request, RequestOrders, RequestOrderItemss
from product.serializers import ProductSerializer


class RequestOrderItemssSerializer(serializers.ModelSerializer):
    class Meta:
        model = RequestOrderItemss
        fields = ('id', 'request_order_id', 'product_id', 'qty')


class RequestOrdersSerializer(serializers.ModelSerializer):
    request_order_itemss = RequestOrderItemssSerializer(many=True)

    class Meta:
        model = RequestOrders
        fields = ('id', 'request_id', 'position', 'destination', 'order_ref', 'request_order_itemss')


class RequestSerializer(serializers.ModelSerializer):
    request_orders = RequestOrdersSerializer(many=True)

    class Meta:
        model = Request
        fields = ('id', 'origin', 'request_orders')

    def create(self, validated_data):
        request_orders_data = validated_data.pop('request_orders')
        request = Request.objects.create(**validated_data)
        for request_order_data in request_orders_data:
            request_order_items_data = request_order_data.pop('request_order_itemss')
            request_order = RequestOrders.objects.create(request_id=request,
                                                                        **request_order_data)
            for request_order_item_data in request_order_items_data:
                RequestOrderItemss.objects.create(request_order_id=request_order,
                                                         **request_order_item_data)
        return request

    def update(self, instance, validated_data):
        request_orders_data = validated_data.pop('request_orders')
        orders = instance.request_orders.all()
        orders = list(orders)
        instance.origin = validated_data.get('origin', instance.origin)
        instance.save()

        for request_order_data in request_orders_data:
            request_order_items_data = request_order_data.pop('request_order_itemss')
            items = instance.request_orders.get().request_order_itemss.all()
            items = list(items)
            for request_order_item_data in request_order_items_data:
                item = items.pop(0)
                item.product_id = request_order_item_data.get('product_id', item.product_id)
                item.qty = request_order_item_data.get('qty', item.qty)
                item.save()
            order = orders.pop(0)
            order.position = request_order_data.get('position', order.position)
            order.destination = request_order_data.get('destination', order.destination)
            order.order_ref = request_order_data.get('order_ref', order.order_ref)
            order.save()
        return instance

and this is my views.py

from django.http import JsonResponse
from rest_framework import generics
from rest_framework.permissions import IsAuthenticated
from request.models import Request, RequestOrders, RequestOrderItemss
from request.serializers import RequestSerializer, RequestOrdersSerializer, \
    RequestOrderItemssSerializer


class RequestListView(generics.ListCreateAPIView):
    queryset = Request.objects.all()
    serializer_class = RequestSerializer
    permission_classes = (IsAuthenticated,)


class RequestView(generics.RetrieveUpdateDestroyAPIView):
    serializer_class = RequestSerializer
    queryset = Request.objects.all()
    permission_classes = (IsAuthenticated,)


class RequestOrdersListView(generics.ListCreateAPIView):
    queryset = RequestOrders.objects.all()
    serializer_class = RequestOrdersSerializer
    permission_classes = (IsAuthenticated,)


class RequestOrdersView(generics.RetrieveUpdateDestroyAPIView):
    serializer_class = RequestOrdersSerializer
    queryset = RequestOrders.objects.all()
    permission_classes = (IsAuthenticated,)


class RequestOrderItemssListView(generics.ListCreateAPIView):
    queryset = RequestOrderItemss.objects.all()
    serializer_class = RequestOrderItemssSerializer
    permission_classes = (IsAuthenticated,)


class RequestOrderItemssView(generics.RetrieveUpdateDestroyAPIView):
    serializer_class = RequestOrderItemssSerializer
    queryset = RequestOrderItemss.objects.all()
    permission_classes = (IsAuthenticated,)

this is my JSON data that i want to save in data base :

{
"origin": "Krishna Rungta",
"request_orders": [
    {
        "position":"2",
        "destination" :"Paris",
        "order_ref":"ref#123",
        "request_order_itemss":[
            {
                "product_id":4,
                "qty":444,
            }
            {
                "product_id":5,
                "qty":33,
            }
        ]
    }
    {
        "position":"3",
        "destination" :"Paris",
        "order_ref":"ref#124",
        "request_order_itemss":[
            {
                "product_id":6,
                "qty":123,
            }
            {
                "product_id":4,
                "qty":54,
            }
        ]
    }
]

}

when I try to test this on Postman I get this error :

Direct assignment to the reverse side of a related set is prohibited. Use request_order_itemss.set() instead.

So I want to know where is the problem and is what i did is right or is there something wrong.

4
  • Welcome to StackOverflow. It would be easier to debug with a full stack trace. Also, where are these "Loading..." models? I'm having a hard time understanding the references to LoadingRequest, loading_request_order_itemss, etc. That said, I would guess that the problem you are seeing is a result of the fact that you are not actually ever calling the nested create method (in RequestSerializer, you just create RequestOrders objects without deserializing the validated data first). Commented Dec 18, 2019 at 17:12
  • apa yang terjadi on your model, LoadingRequestOrders and LoadingRequest??? Commented Dec 18, 2019 at 17:44
  • @RishiG sorry, i edited the model i made some changes but i forget to change all but i don't know where problem is. Can you explain it to me. Commented Dec 18, 2019 at 21:29
  • You still have a call to LoadingRequest.objects.create in RequestSerializer, and you also have not provided an actual stack trace as I suggested, but I think I have a handle on the problem and will answer as well as I can Commented Dec 19, 2019 at 18:15

1 Answer 1

4

The error

The problem here is that you have a twice-nested model, but you are only actually deserializing one layer of it before trying to create the objects. You have created RequestOrderItemssSerializer and RequestOrdersSerializer classes, but you are not actually using them in the create method. If you POST the given JSON object to the /requests/ endpoint, the view will call RequestSerializer.create with the that same object. In your create method, you will then call RequestOrders.objects.create with, e.g.,

request_order_data = {
    "position":"2",
    "destination" :"Paris",
    "order_ref":"ref#123",
    "request_order_itemss": [
        {
            "product_id":4,
            "qty":444,
        }
        {
            "product_id":5,
            "qty":33,
        }
    ]
}

As you can see, the list request_order_itemss has not been properly deserialized and the items have not been created, which is why you are getting the error about trying to directly assign values to the reverse side of the RequestOrderItemss.request_order_id ForeignKey relationship.

Note that the example you pointed to in the docs is designed to show you how to handle this exact error, but only for a single level of hierarchy (creating the individual tracks for a given album).

Simple Solution

The simplest way to solve this, is to do away with the RequestOrderSerializer and RequestOrderItemsSerializer and just add an inner loop to the Request.create method which handles the second nested part. Something like this:

class RequestSerializer(serializers.ModelSerializer):
    ...

    def create(self, validated_data):
        request_orders_data = validated_data.pop('request_orders')
        request = Request.objects.create(**validated_data)
        for request_order_data in request_orders_data:
            ro_items = request_order_data.pop('request_order_itemss')
            order = RequestOrders.objects.create(request_id=request, **request_order_data)
            for ro_item in ro_items:
                RequestOrderItemss.create(request_order_id=order, **ro_item)
        return request

I won't implement and test this, so there are probably bugs in the code as written here, but the concept should be straightforward enough. I've also only handled the create method, but you should be able to treat update by extension.

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

2 Comments

I create the update method but i get this error "get() returned more than one RequestOrders -- it returned 2!" when i try to update more than one Request_Order (it works when i update just one). I edit my serializer to see the update method that i create it. can you help me?
This is not the place for it. Post a new question with the code and a full stack trace. See this article for suggestions on how to ask a good question

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.