Search code examples
python-3.xdjango-modelsdjango-rest-frameworkdjango-serializerdjango-2.1

Saving Nested data in using django serializer class


I have a json data to save to a django model. When i try to save it, i get all sorts of errors and i have tried to work around it, all to no avail. Please help me i am new to django rest framework. This are the models i am inserting into:

class OrderItemDishItem(SoftDeleteModelBase):
    item = models.ForeignKey(DishItem, on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField(default=1)
    price = models.DecimalField(max_digits=5, decimal_places=2,default=0.00)


class OrderItem(SoftDeleteModelBase):
    dish = models.ForeignKey(Dish, on_delete=models.CASCADE)
    items = models.ManyToManyField(OrderItemDishItem, related_name="dish_items")
    quantity = models.PositiveIntegerField(default=1)
    unit_price = models.DecimalField(max_digits=5, decimal_places=2,default=0.00)
    discount_amount = models.DecimalField(max_digits=5, decimal_places=2,default=0.00)
    discount_percent = models.DecimalField(max_digits=5, decimal_places=2,default=0.00)


class Order(SoftDeleteModelBase):
    foodjoint=models.ForeignKey(FoodJoint, on_delete=models.CASCADE, related_name="orders", null=True)
    customer=models.ForeignKey(CustomerProfile,on_delete=models.CASCADE,null=True)
    items = models.ManyToManyField(to=OrderItem, related_name="order")
    total_cost = models.DecimalField(max_digits=5, decimal_places=2,default=0.00)
    discount_amount = models.DecimalField(max_digits=5, decimal_places=2,default=0.00)
    discount_percent = models.DecimalField(max_digits=5, decimal_places=2,default=0.00)

This is my serializer class for each of them:

class OrderItemDishItemSerializer(serializers.ModelSerializer):
    def __init__(self, *args, **kwargs):
        many = kwargs.pop('many', True)
        super(OrderItemDishItemSerializer, self).__init__(many=many, *args, **kwargs)

    class Meta:
        model = models.OrderItemDishItem
        fields = '__all__'
        depth = 1

    def create(self, validated_data):
        dish_item = validated_data.pop("items")


        item_obj = models.OrderItemDishItem.objects.create(**item)

        validated_data["items"]=item_obj
        return super().create(validated_data)


class OrderItemSerializer(serializers.ModelSerializer):
    items = OrderItemDishItemSerializer(many=True)

    def __init__(self, *args, **kwargs):
        many = kwargs.pop('many', True)
        super(OrderItemSerializer, self).__init__(many=many, *args, **kwargs)

    class Meta:
        model = models.OrderItem
        fields = '__all__'

    def create(self, validated_data):
        items = validated_data.pop("items")
        for order in items:
            item =  OrderItemDishItemSerializer(data=order["items"])
            models.OrderItem.objects.create(
                item_id= item.initial_data,
                quantity= order["quantity"],
                unit_price=order['unit_price']
            )
        validated_data["items"]=item.initial_data
        return super().create(validated_data)

class OrderSerializer(serializers.ModelSerializer):
    customer = CustomerSerializer()
    items = OrderItemSerializer(many=True)
    class Meta:
        model = models.Order
        fields = '__all__'
        depth = 1
    def create(self, validated_data):
        user_account= validated_data["customer"].pop("user_account")
        # user_account['password'] = make_password(user_account['password'])
        user = User.objects.create_user(**user_account)

        customer = validated_data.pop("customer")

        customer = models.CustomerProfile.objects.create(
            mobile_number= customer["mobile_number"],
            address= customer["address"],
            user_account= user
        )

        # add OrderItems
        order_items = validated_data.pop("items")
        items =  OrderItemSerializer(data=order_items)

        validated_data["items"] = items.initial_data
        validated_data["customer"] = customer
        # validated_data["customer"]["user_account"] = user
        return super().create(validated_data)

And this is the json data i am posting:

{
  "foodjoint_id": 1,
  "customer": {
    "mobile_number": 2013717123,
    "address": "Sunyani",
    "picture": null,
    "user_account": {
      "username": 2013717123,
      "first_name": "Rahman",
      "last_name": "Lawal",
      "email": "[email protected]",
      "password": "test1234"
    }
  },
  "items": [
    {
      "items": [
        {
          "quantity": 1,
          "price": 22,
          "item": 2
        },
        {
          "quantity": 1,
          "price": 10,
          "item": 4
        },
        {
          "quantity": 1,
          "price": 2,
          "item": 6
        },
        {
          "quantity": 1,
          "price": 0,
          "item": 12
        },
        {
          "quantity": 1,
          "price": 0,
          "item": 13
        },
        {
          "quantity": 1,
          "price": 5,
          "item": 9
        }
      ],
      "unit_price": 22,
      "quantity": 1,
      "dish": 2
    }
  ],
  "total_cost": 0,
  "discount_amount": 0,
  "discount_percent": 0

}

Please how do i save data?

Errors I get:

When a serializer is passed a `data` keyword argument you must call `.is_valid()` before attempting to access the serialized `.data` representation.
You should either call `.is_valid()` first, or access `.initial_data` instead.

Solution

  • I later found out how to do it with the help of the rest-framework documentation http://www.django-rest-framework.org/api-guide/relations/#nested-relationships

    class OrderSerializer(serializers.ModelSerializer):
        customer = CustomerSerializer()
        items = OrderItemSerializer(many=True)
        class Meta:
            model = models.Order
            fields = ('id','foodjoint_id','items','customer','total_cost','discount_amount','discount_percent')
            depth = 1
    
        def create(self, validated_data):
            # get our user info
            customer= validated_data.pop("customer")
            # get order_items
            order_items = validated_data.pop("items")
            # get user info from customer 
            user_account = customer.pop("user_account")
            # create user [1]
            user = User.objects.create_user(**user_account)
    
            # create customer [2]
            customer['user_account']=user
            customer_instance = models.CustomerProfile.objects.create(**customer)
    
            order_items_created=[]
            for item in order_items:
                # get order items dish items
                order_items_dish_items = item.pop("items")
                order_item_instance = models.OrderItem.objects.create(**item)
                for order_item_data in order_items_dish_items:
                    # create orderitemdishitem [3]
                    # dish_item_instance = models.DishItem.objects.filter(id=order_item_data['dish_item_item']).first()
                    order_item_instance.items.add(models.OrderItemDishItem.objects.create(**order_item_data))
                # create order item [4]
                order_items_created.append(order_item_instance)
                
            # create order [5]
            order_instance =   models.Order.objects.create(customer=customer_instance,**validated_data)
            order_instance.items.set(order_items_created)
            return order_instance