Django Rest Framework Many To Many Intermediate Table Serialization Example
models.py
xxxxxxxxxxclass 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
xxxxxxxxxxfrom django.urls import path# internalfrom my.views import Products, Materialsurlpatterns = [ # many to many intermediate using path('products', Products.as_view()), path('materials', Materials.as_view()), ]views.py
xxxxxxxxxxfrom rest_framework.views import APIViewfrom rest_framework import statusfrom rest_framework.response import Response# internalfrom my.models import Product, Material, MaterialProductfrom my.serializers import ProductDisplaySerializer, ProductCreateSerializer, MaterialSerializerclass 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
xxxxxxxxxxfrom rest_framework import serializers# internalfrom my.models import Product, Material, MaterialProductclass 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 productclass 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