Search code examples
djangodjango-rest-frameworkpostmansave

price() missing 1 required positional argument: 'self' while trying to calculate the price in Django Rest Framework


I am trying to create a case where when I call the order create API, the price will be calculated itself and saved in the database but I am getting this error in the Postman.

Error:

price() missing 1 required positional argument: 'self

My models:

class Order(models.Model):
    
    user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)   
    ordered_date = models.DateTimeField(auto_now_add=True)
    ordered = models.BooleanField(default=False)
    total_price = models.CharField(max_length=50,blank=True,null=True)
    #billing_details = models.OneToOneField('BillingDetails',on_delete=models.CASCADE,null=True,blank=True,related_name="order")

    def __str__(self):
        return self.user.email
  
def price(self):
    total_item_price = self.quantity * self.item.varaints.price
    return total_item_price

class OrderItem(models.Model):
    #user = models.ForeignKey(User,on_delete=models.CASCADE, blank=True
    #orderItem_ID = models.UUIDField(max_length=12, editable=False,default=str(uuid.uuid4()))
    orderItem_ID = models.CharField(max_length=12, editable=False, default=id_generator)
    order = models.ForeignKey(Order,on_delete=models.CASCADE, blank=True,null=True,related_name='order_items')
    item = models.ForeignKey(Product, on_delete=models.CASCADE,blank=True, null=True)
    order_variants = models.ForeignKey(Variants, on_delete=models.CASCADE,blank=True,null=True)
    quantity = models.IntegerField(default=1)

    total_item_price = models.PositiveIntegerField(blank=True,null=True,default=price())

    ORDER_STATUS = (
        ('To_Ship', 'To Ship',),
        ('Shipped', 'Shipped',),
        ('Delivered', 'Delivered',),
        ('Cancelled', 'Cancelled',),
    )
    order_item_status = models.CharField(max_length=50,choices=ORDER_STATUS,default='To_Ship')

Here quantity field is present in the OrderItem model itself but the price is present in the Variant model which is related to the Product model like this.

Things I tried:

  1. I tried removing brackets () in price, but got same error.
  2. If I tried putting price function inside class model before total_itel_price field, it says self is required inside bracket of price, and if I put self, = is required and I dont know to put in price(self=??)

Other Models:

Class Variants(models.Model):
    ...#other fields    
    price = models.DecimalField(decimal_places=2, max_digits=20,default=500)

Class Product(models.Model):
    ...#other fields
    variants = models.ManyToManyField(Variants,related_name='products')

My serializer:

class OrderSerializer(serializers.ModelSerializer):

    billing_details = BillingDetailsSerializer()
    order_items = OrderItemSerializer(many=True)
    user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
    class Meta:
        model = Order
        fields = ['id','user','ordered_date','order_status', 'ordered', 'order_items', 'total_price','billing_details']
        # depth = 1   

    def create(self, validated_data):
        user = self.context['request'].user
        if not user.is_seller:
            order_items = validated_data.pop('order_items')
            billing_details = validated_data.pop('billing_details')
            order = Order.objects.create(user=user,**validated_data)
            BillingDetails.objects.create(user=user,order=order,**billing_details)
            for order_items in order_items:
                OrderItem.objects.create(order=order,**order_items)
            
        else:
            raise serializers.ValidationError("This is not a customer account.Please login as customer.")

Updated Code:

class OrderItem(models.Model):   
    
 #total_item_price = models.PositiveIntegerField(blank=True,null=True,default=0) #commented out this field other fields are same as above


order_item_status = models.CharField(max_length=50,choices=ORDER_STATUS,default='To_Ship')

@property
def price(self):
    return self.quantity * self.item.varaints.price

class OrderItemSerializer(serializers.ModelSerializer):    
    order = serializers.PrimaryKeyRelatedField(read_only=True)
    price = serializers.ReadOnlyField()
    class Meta:
        model = OrderItem
        fields = ['id','order','orderItem_ID','item','order_variants', 'quantity','order_item_status','price']
        # depth = 1

Order Serializer is just like above. It includes OrderItemSerializer as shown:

class OrderSerializer(serializers.ModelSerializer):

    billing_details = BillingDetailsSerializer()
    order_items = OrderItemSerializer(many=True)
    user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
    class Meta:
        model = Order
        fields = ['id','user','ordered_date','order_status', 'ordered', 'order_items', 'total_price','billing_details']

Update for Order total_price calculation.

This is what I did for total_price calculation but I am not getting total_price field in the api response, there is no error though.

class Order(models.Model):     
.....#same fields as above

    @property
    def total_order_price(self):
        return sum([_.price for _ in self.order_items_set.all()])

I have used price function in the OrderItem model and my instance of OrderItem is order_items. What is the issue??


Solution

  • This code finally worked for OrderItem price calculation:

    class OrderItem(models.Model): 
    .....#fields same as above
        #total_item_price = models.PositiveIntegerField(blank=True,null=True,default=0)
    
        ORDER_STATUS = (
            ('To_Ship', 'To Ship',),
            ('Shipped', 'Shipped',),
            ('Delivered', 'Delivered',),
            ('Cancelled', 'Cancelled',),
        )
        order_item_status = models.CharField(max_length=50,choices=ORDER_STATUS,default='To_Ship')
    
        @property
        def price(self):
            total_item_price = self.quantity * self.order_variants.price
            return total_item_price
    

    There was a typo in variants. Also, I should be using order_variants instead of item.variants because item has many variants but the user selects only one which has a unique price.