Django Rest Framework CRUD operations
Serializing Many To Many Relationship table
api/models.py
xxxxxxxxxx
from django.db import models
class Material(models.Model):
name = models.CharField(max_length=120)
price = models.FloatField()
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=120)
materials = models.ManyToManyField(Material, through='MaterialProduct')
def __str__(self):
return self.name
class MaterialProduct(models.Model):
""" many to many intermediate table """
material = models.ForeignKey(Material, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
material_ratio = models.FloatField()
Apply models to the database:
python manage.py makemigrations
python manage.py migrate
api/serializers.py
xxxxxxxxxx
from rest_framework import serializers
from .models import Product, Material, MaterialProduct
class MaterialSerializer(serializers.ModelSerializer):
class Meta:
model = Material
fields = '__all__'
class MaterialProductSerializer(serializers.ModelSerializer):
material = MaterialSerializer()
class Meta:
model = MaterialProduct
fields = '__all__'
class ProductSerializer(serializers.ModelSerializer):
# To get materials which are associated with a product
materials = serializers.SerializerMethodField()
class Meta:
model = Product
fields = '__all__'
depth = 1
def get_materials(self, obj):
query_set = MaterialProduct.objects.filter(product=obj)
return [MaterialProductSerializer(item).data for item in query_set]
api/routes.py
xxxxxxxxxx
from rest_framework.views import APIView
from rest_framework.response import Response
from polls.serializers import MaterialSerializer, ProductSerializer, MaterialProductSerializer
from polls.models import Product, Material, MaterialProduct
class ProductList(APIView):
def get(self, request):
products = Product.objects.all()
serializer = ProductSerializer(products, many=True)
return Response(serializer.data)
api/urls.py
xxxxxxxxxx
from django.urls import path
from polls.routes import ProductList
urlpatterns = [
path('api/products', ProductList.as_view(), name='products'),
]
project/urls.py
xxxxxxxxxx
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('',include('api.urls')),
]
- GET request to
http://127.0.0.1:8000/api/products
- Returned data:
xxxxxxxxxx
[
{
"id": 1,
"materials": [
{
"id": 1,
"material": {
"id": 3,
"name": "material3",
"price": 15.0
},
"material_ratio": 20.0,
"product": 1
},
{
"id": 2,
"material": {
"id": 6,
"name": "material6",
"price": 30.0
},
"material_ratio": 80.0,
"product": 1
}
],
"name": "product44"
},
{
"id": 2,
"materials": [],
"name": "product66"
},
{
"id": 3,
"materials": [
{
"id": 6,
"material": {
"id": 1,
"name": "material1",
"price": 5.0
},
"material_ratio": 5.0,
"product": 3
},
{
"id": 7,
"material": {
"id": 2,
"name": "material2",
"price": 10.0
},
"material_ratio": 15.0,
"product": 3
},
{
"id": 8,
"material": {
"id": 4,
"name": "material4",
"price": 20.0
},
"material_ratio": 25.0,
"product": 3
},
{
"id": 9,
"material": {
"id": 8,
"name": "material8",
"price": 50.0
},
"material_ratio": 45.0,
"product": 3
},
{
"id": 10,
"material": {
"id": 10,
"name": "material10",
"price": 1000.0
},
"material_ratio": 10.0,
"product": 3
}
],
"name": "product100"
},
{
"id": 4,
"materials": [],
"name": "product200"
},
{
"id": 5,
"materials": [
{
"id": 3,
"material": {
"id": 2,
"name": "material2",
"price": 10.0
},
"material_ratio": 30.0,
"product": 5
},
{
"id": 4,
"material": {
"id": 4,
"name": "material4",
"price": 20.0
},
"material_ratio": 40.0,
"product": 5
},
{
"id": 5,
"material": {
"id": 8,
"name": "material8",
"price": 50.0
},
"material_ratio": 30.0,
"product": 5
}
],
"name": "product300"
},
{
"id": 6,
"materials": [
{
"id": 11,
"material": {
"id": 5,
"name": "material5",
"price": 25.0
},
"material_ratio": 100.0,
"product": 6
}
],
"name": "product444"
}
]
Product Detail
api/routes.py
xxxxxxxxxx
...
from django.shortcuts import get_object_or_404
class ProductDetail(APIView):
def get(self, request, pk):
product = get_object_or_404(Product, pk=pk)
serializer = ProductSerializer(product)
return Response(serializer.data)
api/urls.py
xxxxxxxxxx
from polls.routes import ProductList, ProductDetail
path('api/products/<int:pk>', ProductDetail.as_view(), name='product-detail'),
- GET request to the
http://127.0.0.1:8000/api/products/5
- Returned data:
xxxxxxxxxx
{
"id": 5,
"materials": [
{
"id": 3,
"material": {
"id": 2,
"name": "material2",
"price": 10.0
},
"material_ratio": 30.0,
"product": 5
},
{
"id": 4,
"material": {
"id": 4,
"name": "material4",
"price": 20.0
},
"material_ratio": 40.0,
"product": 5
},
{
"id": 5,
"material": {
"id": 8,
"name": "material8",
"price": 50.0
},
"material_ratio": 30.0,
"product": 5
}
],
"name": "product300"
}
Create Product | POST request
api/routes.py
xxxxxxxxxx
from rest_framework import status
class ProductList(APIView):
def get(self, request):
#...
def post(self, request, format=None):
serializer = ProductSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
- POST request to the
http://127.0.0.1:8000/api/products
- data :
{"id":integer_number, "name":"new product"}
- returned data:
xxxxxxxxxx
{
"id": 7,
"materials": [],
"name": "new_product"
}
Update Product | PUT request
api/routes.py
xxxxxxxxxx
class ProductDetail(APIView):
def get(self, request, pk):
#...
def put(self, request, pk, format=None):
product = get_object_or_404(Product, pk=pk)
serializer = ProductSerializer(product, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
- PUT request to the
http://127.0.0.1:8000/api/products/6
- data: {"name":"product444updated"}
- returned data:
xxxxxxxxxx
{
"id": 6,
"materials": [
{
"id": 11,
"material": {
"id": 5,
"name": "material5",
"price": 25.0
},
"material_ratio": 100.0,
"product": 6
}
],
"name": "product444updated"
}
Delete Request
api/routes.py
xxxxxxxxxx
class ProductDetail(APIView):
def get(self, request, pk):
#...
def put(self, request, pk, format=None):
#...
def delete(self, request, pk, format=None):
product = get_object_or_404(Product, pk=pk)
product.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
- DELETE request :
curl -X DELETE http://127.0.0.1:8000/api/products/6
Product Material List
api/routes.py
xxxxxxxxxx
class ProductList(APIView):
#...
class ProductDetail(APIView):
#...
class ProductMaterialList(APIView):
def get(self, request, pk):
mp = MaterialProduct.objects.filter(product=pk)
materials = []
for item in mp:
materials.append(item.material)
serializer = MaterialSerializer(materials, many=True)
return Response(serializer.data)
api/urls.py
xxxxxxxxxx
from api.routes import ProductList, ProductDetail, ProductMaterialList
urlpattern = [
path('api/products', ProductList.as_view(), name='products'),
path('api/products/<int:pk>', ProductDetail.as_view(), name='product-detail'),
path('api/products/<int:pk>/materials', ProductMaterialList.as_view(), name='product-material-list'),
]
- GET request to the
http://127.0.0.1:8000/api/products/1/materials
-returned data:
xxxxxxxxxx
[
{
"id": 3,
"name": "material3",
"price": 15.0
},
{
"id": 6,
"name": "material6",
"price": 30.0
}
]
Product's multiple Material Update | bulk update
api/serializers.py
xxxxxxxxxx
class MaterialListSerializer(serializers.ListSerializer):
def update(self, instance, validated_data):
material_mapping = {material.id: material for material in instance}
data_mapping = {item['id']: item for item in validated_data}
result = []
for material_id, data in data_mapping.items():
material = material_mapping.get(material_id, None)
if material is not None:
result.append(self.child.update(material, data))
return result
class MaterialSerializer(serializers.ModelSerializer):
id = serializers.IntegerField()
class Meta:
model = Material
fields = '__all__'
list_serializer_class = MaterialListSerializer
api/routes.py
xxxxxxxxxx
class ProductMaterialList(APIView):
def get(self, request, pk):
#...
def put(self, request, pk, format=None):
mp = MaterialProduct.objects.filter(product=pk)
materials = []
for item in mp:
materials.append(item.material)
serializer = MaterialSerializer(materials, request.data, many=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
- PUT request to the
http://127.0.0.1:8000/api/products/1/materials
- data :
xxxxxxxxxx
[
{"id" : 3, "name" : "material3_UPDATED" , "price" : 200 },
{"id" : 6 , "name" : "material6_UPDATED", "price" : 600 }
]
- returned_data:
xxxxxxxxxx
[
{
"id": 3,
"name": "material3_UPDATED",
"price": 200.0
},
{
"id": 6,
"name": "material6_UPDATED",
"price": 600.0
}
]
Yorumlar