Sesshōmaru
Sesshōmaru

Reputation: 45

Cannot assign "1": "Refund.order" must be a "Order" instance

So, this here is a dirty production-level code, and I am stuck at this. I am designing a Return API but I am not good at this, help is much appreciated.

Traceback (most recent call last):
  File "C:\Users\Abdul\.virtualenvs\storefront\lib\site-packages\django\core\handlers\exception.py", line 55, in inner
    response = get_response(request)

  File "C:\Users\Abdul\.virtualenvs\storefront\lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)

  File "C:\Users\Abdul\.virtualenvs\storefront\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)

  File "C:\Users\Abdul\.virtualenvs\storefront\lib\site-packages\rest_framework\viewsets.py", line 125, in view
    return self.dispatch(request, *args, **kwargs)

  File "C:\Users\Abdul\.virtualenvs\storefront\lib\site-packages\rest_framework\views.py", line 509, in dispatch
    response = self.handle_exception(exc)

  File "C:\Users\Abdul\.virtualenvs\storefront\lib\site-packages\rest_framework\views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)

  File "C:\Users\Abdul\.virtualenvs\storefront\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception
    raise exc

  File "C:\Users\Abdul\.virtualenvs\storefront\lib\site-packages\rest_framework\views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)

  File "C:\Users\Abdul\Documents\storefront\accounts\views.py", line 115, in create
    order = serializer.save()

  File "C:\Users\Abdul\Documents\storefront\accounts\serializers.py", line 155, in save
    refund.order = order_id

  File "C:\Users\Abdul\.virtualenvs\storefront\lib\site-packages\django\db\models\fields\related_descriptors.py", line 235, in __set__
    raise ValueError(
ValueError: Cannot assign "1": "Refund.order" must be a "Order" instance.

views.py:

class RefundViewSet(ModelViewSet):
    http_method_names = ['get', 'post', 'delete', 'head', 'options']

    def get_permissions(self):
        if self.request.method == 'POST':
            return [IsAdminUser()]
        return [IsAuthenticated()]

    def create(self, request, *args, **kwargs):
        serializer = RefundOrderSerializer(
            data=request.data,
            context={'user_id': self.request.user.id})
        serializer.is_valid(raise_exception=True)
        order = serializer.save()
        serializer = OrderSerializer(order)
        return Response(serializer.data)
    def get_serializer_class(self):
        if self.request.method == 'POST':
            return RefundOrderSerializer
        return OrderSerializer

    def get_queryset(self):
        user = self.request.user
        if user.is_staff:
            return Order.objects.all()
        customer_id = Customer.objects.only('id').get(user_id=user.id)
        return Order.objects.filter(customer_id=customer_id)

I don't think this part has any problems.

serializers.py:

class RefundOrderSerializer(serializers.Serializer):
    order_id = serializers.IntegerField()

###validator methods to ensure that only a customer with an order can request a refund.###

    def validated_order_id(self, order_id):
        if not Order.objects.filter(pk=order_id).exist():
            raise serializers.ValidationError('No order with given id was found.')
        return order_id

    def save(self, **kwargs):
        with transaction.atomic():
            order_id = self.validated_data['order_id']
            message = serializers.CharField(max_length=500)
            email = serializers.EmailField()

            refund = Refund()
            refund.order = order_id
            refund.reason = message
            refund.email = email
            refund.save()

            return refund

This is the Problem Part

models.py:

class Customer(models.Model):
    MEMBERSHIP_BRONZE = 'B'
    MEMBERSHIP_SILVER = 'S'
    MEMBERSHIP_GOLD = 'G'
    MEMBERSHIP_DIAMOND = 'D'
    MEMBERSHIP_CHOICES = [

        (MEMBERSHIP_BRONZE, 'BRONZE'),
        (MEMBERSHIP_SILVER, 'SILVER'),
        (MEMBERSHIP_GOLD, 'GOLD'),
        (MEMBERSHIP_DIAMOND, 'DIAMOND')

    ]

    phone = models.CharField(max_length=255)
    birth_date = models.DateField(null=True, blank=True)
    customer_subscription = models.CharField(max_length=1, choices=MEMBERSHIP_CHOICES, default=MEMBERSHIP_BRONZE)
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    company = models.CharField(max_length=255)

    def __str__(self):
        return f'{self.user.first_name} {self.user.last_name} {self.customer_subscription}'

    @admin.display(ordering='user__first_name')
    def first_name(self):
        return self.user.first_name

    @admin.display(ordering='user__last_name')
    def last_name(self):
        return self.user.last_name

    class Meta:
        ordering = ['user__first_name', 'user__last_name']
        permissions = [
            ('view_history', 'Can view history')
        ]



class Order(models.Model):
    ORDER_STATUS_PENDING = 'P'
    ORDER_STATUS_FAILED = 'F'
    ORDER_STATUS_COMPLETED = 'C'
    ORDER_STATUS_CANCELLED = 'D'
    ORDER_STATUS_CHOICES = [

        (ORDER_STATUS_PENDING, 'PENDING'),
        (ORDER_STATUS_CANCELLED, 'CANCELLED'),
        (ORDER_STATUS_FAILED, 'FAILED'),
        (ORDER_STATUS_COMPLETED, 'COMPLETED')

    ]
    id = models.IntegerField(primary_key=True)
    placed_at = models.DateTimeField(auto_now_add=True)
    order_status = models.CharField(max_length=1, choices=ORDER_STATUS_CHOICES, default=ORDER_STATUS_PENDING)
    customer = models.ForeignKey(Customer, on_delete=models.PROTECT, null=True)
    refund_requested = models.BooleanField(default=False)
    refund_granted = models.BooleanField(default=False)

    class Meta:
        permissions = [
            ('cancel_order', 'Can Cancel Order')
        ]


class OrderItem(models.Model):
    order = models.ForeignKey(Order, on_delete=models.PROTECT, related_name='items')
    product = models.ForeignKey(Product, on_delete=models.PROTECT, related_name="orderitems")
    quantity = models.PositiveSmallIntegerField()
    unit_price = models.DecimalField(max_digits=6, decimal_places=2)

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


class Cart(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid4)
    created_at = models.DateTimeField(auto_now_add=True)


class CartItem(models.Model):
    cart = models.ForeignKey(Cart, on_delete=models.CASCADE, related_name='items')
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    quantity = models.PositiveSmallIntegerField()

    class Meta:
        unique_together = [['cart', 'product']]


class Refund(models.Model):
    order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='refunds')
    reason = models.TextField()
    accepted = models.BooleanField(default=False)
    email = models.EmailField()

    def __str__(self):
        return f"{self.pk}"

Used this code as an example from justdjango. just the Refund part.

I tried a lot of techniques to no avail with different results. Even advices are appreciated.

Upvotes: 0

Views: 174

Answers (1)

Michael Ruth
Michael Ruth

Reputation: 3504

Assign an Order instance rather than the order ID to refund.order. You'll need to query for the matching order. This is indicated in the Refund model by

order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='refunds')

and in the error

`ValueError: Cannot assign "1": "Refund.order" must be a "Order" instance.`
class RefundOrderSerializer(serializers.Serializer):
    order_id = serializers.IntegerField()

###validator methods to ensure that only a customer with an order can request a refund.###

    def validated_order_id(self, order_id):
        if not Order.objects.filter(pk=order_id).exist():
            raise serializers.ValidationError('No order with given id was found.')
        return order_id

    def save(self, **kwargs):
        with transaction.atomic():
            order_id = self.validated_data['order_id']
            message = serializers.CharField(max_length=500)
            email = serializers.EmailField()

            refund = Refund()
            
            # Solution in context
            refund.order = Order.objects.get(pk=order_id)
            
            refund.reason = message
            refund.email = email
            refund.save()

            return refund

Upvotes: 1

Related Questions