Reputation: 1042
I am trying to make update API for order objects. OrderItem
model is in many to one relationship (with Foreignkey
) with Order
Model. Also, Billing Details model is one to one relationship with Order
model. I am able to update Billing details fields and also Order
fields, but can't update the OrderItem
fields.
I got this error saying:
'RelatedManager' object has no attribute 'save'
My models:
class Order(models.Model):
ORDER_STATUS = (
('To_Ship', 'To Ship',),
('Shipped', 'Shipped',),
('Delivered', 'Delivered',),
('Cancelled', 'Cancelled',),
)
user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)
order_status = models.CharField(max_length=50,choices=ORDER_STATUS,default='To_Ship')
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
class Meta:
verbose_name_plural = "Orders"
ordering = ('-id',)
class OrderItem(models.Model):
#user = models.ForeignKey(User,on_delete=models.CASCADE, blank=True)
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)
# def price(self):
# total_item_price = self.quantity * self.item.varaints.price
# return total_item_price
total_item_price = models.PositiveIntegerField(blank=True,null=True,)
def __str__(self):
return f"{self.quantity} items of {self.item} of {self.order.user}"
class Meta:
verbose_name_plural = "Cart Items"
ordering = ('-id',)
class BillingDetails(models.Model):
PAYMENT_TYPE = (
('cash_on_delivery', 'Cash On Delivery',),
('credit/debit_card', 'Credit/Debit Card',),
('connect_ips', 'Connect IPS',),
('fonepay', 'Fonepay',),
)
user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)
order = models.OneToOneField(Order, on_delete=models.CASCADE, blank=True, null=True, related_name='billing_details')
address = models.CharField(max_length=100,blank=True,null=True)
postal = models.CharField(max_length=50,blank=True,null=True)
payment_type = models.CharField(max_length=50,blank=True,null=True,choices=PAYMENT_TYPE,default='cash_on-delivery')
def __str__(self):
return self.address
class Meta:
verbose_name_plural= "Shipping Address"
MY VIEWS:
class UpdateOrderView(UpdateAPIView):
permission_classes = [AllowAny]
queryset = Order.objects.all()
serializer_class = OrderUpdateSerializer
My serializers:
class OrderUpdateSerializer(serializers.ModelSerializer):
order_items = OrderItemSerializer(many=True)
billing_details = BillingDetailsSerializer()
class Meta:
model = Order
fields = ['ordered','order_status','order_items','billing_details']
def update(self, instance, validated_data):
instance.order_status = validated_data.get('order_status')
instance.ordered = validated_data.get('ordered')
billing_details_data = validated_data.pop('billing_details',None)
if billing_details_data is not None:
instance.billing_details.address = billing_details_data['address']
instance.billing_details.save() #no-error here
order_items_data = validated_data.pop('order_items')
for order_items_data in order_items_data:
instance.order_items.quantity = order_items_data['quantity']
instance.order_items.order_item_status = order_items_data['order_item_status']
instance.order_items.save() #got the error here
#super(OrderUpdateSerializer, self).update(instance.order_items,validated_data).save()
#super().save()
return super().update(instance,validated_data)
There is no error in instance.billing_details.save()
, but the same code instance.order_items.save()
generates the above error. If I remove instance.order_items.save()
, then it works but it doesn't save the updated data in the database.
Upvotes: 2
Views: 310
Reputation: 16515
You are using OneToOneField
in one but ForeignKey
in the other model, so you cannot use the same code for both.
class OrderItem(models.Model):
...
order = models.ForeignKey(..., related_name='order_items')
...
class BillingDetails(models.Model):
...
order = models.OneToOneField(..., related_name='billing_details')
...
The instance.billing_details
will return an BillingDetails
instance (if there is one) because it is a OneToOneField
, but instance.order_items
will return a related manager for OrderItem
, not an instance.
Solutions:
change the field OrderItem.order
to OneToOneField
; but I don't know if that fits your use case, so you have to analyze it in detail if it will work for you.
instance.order_items.first()
(or instance.order_items.get(...)
) to get get an instance from the related manager.
Upvotes: 2