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
CodePudding user response:
I got solved the error, I wasn't passing the right values is the useState() function.