python - Django Rest框架中多对多中间模型的实现方法

标签 python django django-rest-framework django-serializer

  • 我想听听您的意见,这种方法正确吗?
  • 如何更好地序列化 m2m 中间模型?
  • 我想知道如何组合 DisplayCreate 序列化器。
  • models.py
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)
  • views.py
class Products(APIView):
    def get(self, request, format=None):
        products = Product.objects.all()
        serializer = ProductDisplaySerializer(products, many=True) # Display
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = ProductCreateSerializer(data=request.data) # Create
        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

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
  • 显示的数据:
 {
        "id": 29,
        "name": "product 4",
        "materials": [
            {
                "material_id": 3,
                "rate": 30
            },
            {
                "material_id": 2,
                "rate": 70
            }
        ]
    }

创建要发送的数据:

{
    "name" : "product 4",
    "materials" : [
        {
            "material_id":3,
            "rate" : 30
        }   
        ,{
            "material_id":2,
            "rate" : 70
        }

    ]
}

创建后返回的数据:

  • 注意:它正确保存了数据,但不显示如下!
{
    "id": 29,
    "name": "product 4",
    "materials": [
        {},
        {}
    ]
}

最佳答案

您可以使用RetrieveAPIView用于显示和 CreateAPIView for create 是内置功能,可以使事情变得更简单,并且其他开发人员可以更轻松地使用您的代码,因为他们需要熟悉的是 DRF 的工作方式,而不是您编写代码的方式。基本上最好遵循其他开发人员熟悉的模式。

我不建议组合创建和显示序列化器,除非它们非常简单。如果它们变得有点复杂,那么调试或进行更改可能会变得困难,特别是当其他人正在调试您的代码时!

对于序列化 m2m,materials = ProductMaterialRateSerializer(many=True)是正确的方法,为了创建,您可以使用内置功能,但如果它很复杂并且需要一些计算,那么我建议覆盖 saveupdate创建序列化程序中的方法。

对于返回的数据:

您可以像这样覆盖上下文:

def post(self, request, format=None):
    serializer = ProductCreateSerializer(data=request.data) # Create
    if serializer.is_valid():

        # Get the saved object
        saved_obj = serializer.save()

        # Serialize the saved object with the preferred serializer.
        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)

关于python - Django Rest框架中多对多中间模型的实现方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55278053/

相关文章:

python - 响应没有属性 'username'

python - 在 Django-REST-framework 中对 ModelViewSet 使用 defaultRouter() 时出现错误的重定向

python - 如何使用 DRF JWT 实现记住我功能?

python - 是否可以使用有序字典或列表进行绘图,OrderedDict 不起作用

python - python中的时间间隔重叠

python - 将二进制数据打包和解包到列表中的最快方法

python - Django 中 ForeignKeys、ManyToMany 和 GenericForeignKeys 的最佳实践

python 3.5 - django 1.10 - mysqlclient windows 7安装错误

python - 如何限制 Flask 中的事件登录数

python - Django Rest Framework SerializerMethodField 传递额外参数