0

I am working on Restaurant Ordering Application. Order of items will be created as an Array of JSON object will be POSTed to orderdetail models, but when the stock of any of the item is not sufficient it will raise Exception. But I only can give an error for one item not all the items.

For example:

Current Stock

Apple 5pcs

Mango 10pcs

When I make an order of Apple 10pcs and Mango 20pcs. I want to get an Error Message saying that "Apple and Mango stock is not sufficient". But currently, I only get "Apple stock is not sufficient" because I put apple as the first object in the array. If I put mango as the first object, I will get "Mango stock is not sufficient".

For full of the code, you can check the repo link: here. My Models:

class Menu(models.Model):
    image = models.ImageField(upload_to=path_and_rename)
    name = models.CharField(max_length=100)
    price = models.IntegerField()
    category = models.IntegerField()
    availability = models.BooleanField(default=False)
    qty = models.IntegerField(default=100)
    sellerID = models.ForeignKey(Seller, on_delete=models.PROTECT)


class OrderDetail(models.Model):
    orderID = models.ForeignKey(Order, on_delete=models.PROTECT)
    menuID = models.ForeignKey(Menu, on_delete=models.PROTECT)
    price = models.IntegerField()
    qty = models.IntegerField()
    tableNumber = models.IntegerField()
    done = models.BooleanField(default=False)
    # orderTime = models.DateTimeField(auto_now_add=True)
    # finishTime = models.DateTimeField(auto_now=True)
    finishTime = models.DateTimeField(null=True, blank=True)
    sellerID = models.ForeignKey(Seller, on_delete=models.PROTECT)

    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
        if self.done:
            self.finishTime = datetime.datetime.now()
        else:
            menuID = self.menuID.id
            menuObject = Menu.objects.get(id=menuID)
            tempQty = menuObject.qty - self.qty
            if tempQty>=0:
                menuObject.qty = tempQty
                menuObject.save()
            else:
                # return serializers.ValidationError()
                raise serializers.ValidationError(menuObject.name + ": STOCK IS NOT SUFFICIENT")
        super().save(force_insert, force_update, using, update_fields)

My View:

class OrderDetailViewset(viewsets.ModelViewSet):
    serializer_class = serializers.OrderDetailSerializer
    def get_queryset(self):
        queryset = models.OrderDetail.objects.all()
        sellerID = self.request.query_params.get('sellerID', None)
        done = self.request.query_params.get('done', None)
        if sellerID is not None:
            queryset = queryset.filter(sellerID=sellerID)
            if done is not None:
                queryset = queryset.filter(sellerID=sellerID, done=done)
        return queryset

    # Enable Post of List
    # https://stackoverflow.com/questions/37329771/django-rest-bulk-post-post-array-of-json-objects
    # Accessed on March 9, 2019
    def create(self, request, pk=None, company_pk=None, project_pk=None):
        is_many = True if isinstance(request.data, list) else False

        serializer = self.get_serializer(data=request.data, many=is_many)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

I think the problem is located where I raised the Exception, but I have no Idea how to fix it. Thank you before!

7
  • 1
    Move the validation you're doing in model save to serializer's validate methods. For each field define a validate_{field_name} method. This way it will collect all field errors before raising an exception and you will get all errors Commented Mar 26, 2019 at 10:11
  • @Ken4scholars sorry I can't imagine how to do that, could you provide me a snippet/example of that code? I'm new in the backend Commented Apr 20, 2019 at 3:27
  • It's explained in this part of the docs django-rest-framework.org/api-guide/serializers/#validation Commented Apr 20, 2019 at 11:39
  • @Ken4scholars if I add validation in the serialization, does it make an impact on the result (reply) of the GET request? Or the validation will take place only when I make POST request? Commented Apr 24, 2019 at 11:01
  • 1
    You can check self.context.request.method in the serializer to determine the HTTP method and do the appropriate check. Commented May 17, 2019 at 5:20

1 Answer 1

1

as you correctly said the problem is located where you raised the Exception: ModelViewSet.create > serializer.is_valid(raise_exception=True).

Based on the DRF docs:

When deserializing data, you always need to call is_valid() before attempting to access the validated data, or save an object instance.

...

The .is_valid() method takes an optional raise_exception flag that will cause it to raise a serializers.ValidationError exception if there are validation errors.

These exceptions are automatically dealt with by the default exception handler that REST framework provides, and will return HTTP 400 Bad Request responses by default.

So, the first object who reaches this validation returns the HTTP 400 Bad Request you mention.

You'll need to customize the validation to not return an HTTP 400 Bad Request, implement your own validation in the serializer and/or catch and process these exception in the view, that way you'll have the flexibility you need to handle these bulk load.

Take a look at DRF code and DRF docs.

Good Luck!

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

1 Comment

sorry I can't imagine how to do that, could you provide me a snippet/example of that code? I'm new in the backend

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.