Django.fun

How do you add validation to django rest framework api

I have two models, which look like this:

class Item(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=60)
    sku = models.CharField(max_length=60)
    description = models.TextField()
    price = models.DecimalField(max_digits=6, decimal_places=2)
    location = models.CharField(max_length=60)
    serial_number = models.CharField(max_length=60)

    def __str__(self):
        return self.name

class Warehouse(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=60)

    def __str__(self):
        return self.name

and they have two serializers which look like this:

class ItemSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Item
        fields = ('id', 'name', 'sku', 'description', 'price', 'location', 'serial_number')
        #we need a validator that checks if location is in the list of warehouses
        #we need a validator that checks if sku is in the list of products
    

class WarehouseSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Warehouse
        fields = ('id', 'name')
        

I need a way to ensure that the location field for newly created items matches an existing name field from a warehouse. I also need the deletion of a warehouse to trigger the deletion of all items in that warehouse, or, failing that; if the warehouse has items, it cannot be deleted.

I'm brand new to python and django, so any help would be massively appreciated!

for reference, my views class looks like

class ItemViewSet(viewsets.ModelViewSet):
    queryset = Item.objects.all().order_by('name')
    serializer_class = ItemSerializer

class WarehouseViewSet(viewsets.ModelViewSet):
    queryset = Warehouse.objects.all().order_by('name')
    serializer_class = WarehouseSerializer

if that helps, but from what I can see I don't expect it to. Thanks in advance!

Answers: 1

Answered by Josewails, Jan. 13, 2022, 8:46 a.m.

I think the problem here is your data models. It's clear that a warehouse and an item have a one to many relationship. With that, you would have something like this in your models.

from django.db import models


class Warehouse(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=60)

    def __str__(self):
        return self.name


class Item(models.Model):
    id = models.AutoField(primary_key=True)
    warehouse = models.ForeignKey(Warehouse, related_name="items", on_delete=models.CASCADE)
    name = models.CharField(max_length=60)
    sku = models.CharField(max_length=60)
    description = models.TextField()
    price = models.DecimalField(max_digits=6, decimal_places=2)
    location = models.CharField(max_length=60)
    serial_number = models.CharField(max_length=60)

    def __str__(self):
        return self.name

The on_delete=models.CASCADE will ensure that all items related to a warehouse are deleted when a warehouse is deleted. The foreign key relationship will ensure that warehouse id you provide when creating the item, exists before the item is created.

The other files will look as follows.

serializers.py

from rest_framework import serializers

from .models import Warehouse, Item


class ItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = Item
        fields = ('id', 'name', 'sku', 'description', 'price', 'location', 'serial_number', "warehouse")


class WarehouseSerializer(serializers.HyperlinkedModelSerializer):
    items = serializers.StringRelatedField(many=True, required=False)

    class Meta:
        model = Warehouse
        fields = ('id', 'name', 'items')

views.py

from .models import Item, Warehouse
from .serializers import ItemSerializer, WarehouseSerializer

from rest_framework import viewsets


class ItemViewSet(viewsets.ModelViewSet):
    queryset = Item.objects.all().order_by('name')
    serializer_class = ItemSerializer


class WarehouseViewSet(viewsets.ModelViewSet):
    queryset = Warehouse.objects.all().order_by('name')
    serializer_class = WarehouseSerializer