Django Rest Framework Many To Many Intermediate Table Serialization Example
models.py
xxxxxxxxxx
class Material(models.Model):
name = models.CharField(max_length=120)
class Product(models.Model):
name = models.CharField(max_length=120)
materials = models.ManyToManyField(Material, through='MaterialProduct')
class MaterialProduct(models.Model):
material = models.ForeignKey(Material, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
rate = models.FloatField(default=100)
urls.py
xxxxxxxxxx
from django.urls import path
# internal
from my.views import Products, Materials
urlpatterns = [
# many to many intermediate using
path('products', Products.as_view()),
path('materials', Materials.as_view()),
]
views.py
xxxxxxxxxx
from rest_framework.views import APIView
from rest_framework import status
from rest_framework.response import Response
# internal
from my.models import Product, Material, MaterialProduct
from my.serializers import ProductDisplaySerializer, ProductCreateSerializer, MaterialSerializer
class Products(APIView):
def get(self, request, format=None):
products = Product.objects.all()
serializer = ProductDisplaySerializer(products, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = ProductCreateSerializer(data=request.data)
if serializer.is_valid():
saved_obj = serializer.save()
response_data = ProductDisplaySerializer(saved_obj).data
return Response(response_data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class Materials(APIView):
def get(self, request, format=None):
products = Material.objects.all()
serializer = MaterialSerializer(products, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = MaterialSerializer(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)
serializers.py
xxxxxxxxxx
from rest_framework import serializers
# internal
from my.models import Product, Material, MaterialProduct
class MaterialSerializer(serializers.ModelSerializer):
class Meta:
model = Material
fields = '__all__'
class ProductMaterialRateSerializer(serializers.ModelSerializer):
material = MaterialSerializer(read_only=True)
material_id = serializers.PrimaryKeyRelatedField(
write_only=True, source='material', queryset=Material.objects.all())
class Meta:
model = MaterialProduct # attention!!!
fields = ('material', 'material_id', 'rate')
class ProductCreateSerializer(serializers.ModelSerializer):
'''To create a product with existed material and a material rate(extra field) '''
materials = ProductMaterialRateSerializer(many=True)
class Meta:
model = Product
fields = ('id', 'name', 'materials')
def create(self, validated_data):
materials_data = validated_data.pop('materials')
product = Product.objects.create(**validated_data)
for material_data in materials_data:
MaterialProduct.objects.create(
product=product,
material=material_data.get('material'),
rate=material_data.get('rate'))
return product
class MaterialProductSerializer(serializers.ModelSerializer):
class Meta:
model = MaterialProduct
fields = ('material_id', 'rate')
class ProductDisplaySerializer(serializers.ModelSerializer):
'''To display product with related materials '''
materials = serializers.SerializerMethodField()
class Meta:
model = Product
fields = ('id', 'name', 'materials')
def get_materials(self, product_instance):
query_datas = MaterialProduct.objects.filter(product=product_instance)
return [MaterialProductSerializer(material).data for material in query_datas]
- POST request data:
xxxxxxxxxx
{
"name" : "product 5",
"materials" : [
{
"material_id":1,
"rate" : 30
}
,{
"material_id":2,
"rate" : 70
}
]
}
- Returned:
xxxxxxxxxx
{
"id": 30,
"name": "product 5",
"materials": [
{
"material_id": 1,
"rate": 30
},
{
"material_id": 2,
"rate": 70
}
]
}
- GET request
xxxxxxxxxx
[
{
"id": 29,
"name": "product 4",
"materials": [
{
"material_id": 3,
"rate": 30
},
{
"material_id": 2,
"rate": 70
}
]
},
{
"id": 30,
"name": "product 5",
"materials": [
{
"material_id": 1,
"rate": 30
},
{
"material_id": 2,
"rate": 70
}
]
}
]
Yorumlar