How can I handle 400 bad request error using DRF in Django

Question:

I am trying to perform a POST request using DRF in Django, the program is raising a 400 error (this is the error, Bad Request: /api/menu_items/, the frontend is raising the following error (This field is required) the problem is I cannot see the exact field that is missing. How can I locate the missing field? The error occurs when I try to post a new Menu item.

This is the place model

# Place models 
class Place(models.Model):
    # When User is deleted the Place gets deleted too
    owner = models.ForeignKey(User, on_delete=models.CASCADE)
    name = models.CharField(max_length=255)
    image = models.CharField(max_length=255)
    number_of_tables = models.IntegerField(default=1)
    
    def __str__(self):
      return "{}/{}".format(self.owner.username, self.name)  

This is the Menu Item model


class MenuItem(models.Model):
  place = models.ForeignKey(Place, on_delete=models.CASCADE)
  category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="menu_items")
  name = models.CharField(max_length=255)
  description = models.TextField(blank=True)
  price = models.IntegerField(default=0,)
  image = models.CharField(max_length=255)
  is_available = models.BooleanField(default=True)
  
  def __str__(self):
    return "{}/{}".format(self.category, self.name)

Below are the serialisers.

The error is occurring in the MenuItemSerializer.

from rest_framework import serializers
from . import models

class MenuItemSerializer(serializers.ModelSerializer):
  class Meta:
    model = models.MenuItem
    fields = ('id', 'name', 'description', 'price', 'image', 'is_available', 'place', 'category')
        
class CategorySerializer(serializers.ModelSerializer):
    menu_items = MenuItemSerializer(many=True, read_only=True)
    
    class Meta:
        model = models.Category
        fields = ('id', 'name', 'menu_items', 'place')

class PlaceDetailSerializer(serializers.ModelSerializer):
    categories = CategorySerializer(many=True, read_only=True)
    
    class Meta:
        model = models.Place
        fields = ('id','name','image','number_of_tables','categories',)
class PlaceSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Place
        fields = ('id', 'name', 'image')

Following are the views


from rest_framework import generics
from . import models, serializers, permissions
from django.core.exceptions import BadRequest
#Place Views
class PlaceList(generics.ListCreateAPIView):
    serializer_class = serializers.PlaceSerializer
    
    # Filtering content
    def get_queryset(self):
        return models.Place.objects.filter(owner_id=self.request.user.id)
    # Only the user of a place can make changes

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)


class PlaceDetail(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = [permissions.IsOwnerOrReadOnly] #passing permissions
    serializer_class = serializers.PlaceDetailSerializer
    queryset = models.Place.objects.all()

# Category List
class CategoryList(generics.CreateAPIView):
    permission_classes = [permissions.PlaceOwnerOrReadOnly]
    serializer_class = serializers.CategorySerializer
 
#  Category Details
#No direct relation between Place and Category
class CategoryDetail(generics.UpdateAPIView, generics.DestroyAPIView):
    serializer_class = serializers.CategorySerializer
    queryset = models.Place.objects.all()

# Menu Items
class MenuItemList(generics.CreateAPIView):
    serializer_class = serializers.MenuItemSerializer
    permission_classes = [permissions.PlaceOwnerOrReadOnly]
    
  
   

# Menu Item Details
class MenuItemDetail(generics.UpdateAPIView, generics.DestroyAPIView):
    permission_classes = [permissions.PlaceOwnerOrReadOnly]
    serializer_class = serializers.MenuItemSerializer
    queryset = models.MenuItem.objects.all()


This is the UI code for the Menu Form

import { Button, Form, Overlay } from 'react-bootstrap';
import Popover from 'react-bootstrap/Popover';
import {  RiPlayListAddFill } from 'react-icons/ri';
import { toast } from 'react-toastify';
import { addCategory, addMenuItems } from '../apis';

import ImageDropzone from './ImageDropZone';
import AuthContext from '../contexts/AuthContext';
import { useState, useRef,useContext } from 'react';

    
function MenuItemForms({ place, onDone }) {
    const [categoryName, setCategoryName] = useState("");
    const [categoryFormShow, setCategoryFormShow] = useState(false);
    const [category, setCategory] = useState("");
    
    const [itemName, setItemName] = useState("");
    const [price, setPrice] = useState(itemName.price || 0);
    const [description, setDescription] = useState(itemName.description);
    const [image, setImage] = useState("");
    const [isAvailable, setIsAvailable] = useState(true);

    

    

    const target = useRef(null);

    const auth = useContext(AuthContext);

    //Adding category event
    const onAddCategory = async () => {
        const json = await addCategory({ name: categoryName, place: place.id }, auth.token)
        console.log(json)
        if (json) {
            toast(`Category ${json.name} was created.`, { type: "success" });
            setCategory(json.id);
            setCategoryName("");
            setCategoryFormShow(false);
            onDone();
        }
    }



    const onAddMenuItems = async () => {
        const json = await addMenuItems({
            place: place.id,
            category,
            itemName,
            price,
            description,
            image,
            is_Available: isAvailable,
        }, auth.token);

        if (json) {
            toast(`Menu Item ${json.name} was created`);

            setCategory("");
            setItemName("");
            setPrice(0);
            setDescription("");
            setImage("");
            setIsAvailable(true);
            onDone()
        }
       
    }


  return (
      <div>
          {/* Category Form */}
          <Form.Group>
              <Form.Label>Category</Form.Label>
              <Form.Control as="select" value={ category } onChange={ (e) => setCategory(e.target.value) }>
                  <option />
                  { place?.categories?.map((c) => (
                      <option key={ c.id } value={ c.id }>
                          { c.name }
                      </option>
                  )) }
              </Form.Control>


              {/* Here */ }
              
              <Button variant="link" ref={ target } onClick={ () => setCategoryFormShow(true) }>
                 <RiPlayListAddFill />
              </Button>
              <Overlay
                  target={ target.current } 
                  show={ categoryFormShow } 
                  placement="right"
                  rootClose
                  onHide={() => setCategoryFormShow(false)}
              
              >
                  
                  <Popover id="popover-contained">
                      <Popover.Header as="h3">Category</Popover.Header>
                      <Popover.Body>
                          <Form.Group>
                              <Form.Control
                                  type="text"
                                  placeHolder="Category Name"
                                  value={ categoryName }
                                  onChange={(e) => setCategoryName(e.target.value)}
                              />
                          </Form.Group>
                          <Button className="mt-2" variant="standard"  block onClick={onAddCategory}>
                              Add Category
                          </Button>
                      </Popover.Body>
                  </Popover>
              </Overlay>
             
          </Form.Group>

          <Form.Group>
              <Form.Label>Name</Form.Label>
              <Form.Control
                  type="text"
                  placeholder= "Enter item name"
                  value={ itemName }
                  onChange={(e) => setItemName(e.target.value)}
              />
          </Form.Group>
{/* Price input */}
          <Form.Group>
              <Form.Label>Price</Form.Label>
              <Form.Control
                  type="number"
                  placeholder="Enter the price.."
                  value={ price }
                   
                  onChange={ (e) => setPrice(e.target.value) }
              />
          </Form.Group>
{/* Description */}
          <Form.Group>
              <Form.Label>Description</Form.Label>
              <Form.Control
                  type="text"
                  placeholder="Enter Description.."
                  value={ description }
                  onChange={ (e) => setDescription(e.target.value) }
              />
          </Form.Group>

          {/* Image */ }
          <Form.Group>
              <Form.Label>Image</Form.Label>
              <ImageDropzone value={image} onChange={setImage} />
          </Form.Group>
          
          <Form.Group>
              <Form.Check className='m-1'
                  type="checkbox"
                  label="Is available"
                  checked={ isAvailable }
                  onChange={(e) => setIsAvailable(e.target.checked)}
              />
          </Form.Group>
          <Button variant="standard" block onClick={onAddMenuItems}>
              + Add Menu Iten
          </Button>
          
    </div>
  )
}

export default MenuItemForms

Asked By: Jamoni Jamo

||

Answers:

I got the error solved, I wasn’t passing the right values is the useState() function.

Answered By: Jamoni Jamo