在我的DB设计中,我有一个多到多的关系,我在POST方面遇到了麻烦。我目前有一个名为Load、Containers和Container_Loads的表(这是中间表)。
我的问题是:我希望能够向ContainerLoad中间表发送一个POST请求,并使用它所需的值更新该表,这些值是: Load ID ( Load表的PK)、Container (容器表的PK)和#的托盘(中间表的唯一字段)。我能够很好地获取/检索记录,但是当我试图发送带有有效负载的POST请求时,例如
{
        "id":3,
        "pallets":"4",
        "containerNumberId":5,
        "loadNumberId":53
}(其中containerNumberID和loadNumberID是各自表中的现有键),我的代码似乎也希望创建一个全新的加载条目(正如它向我请求加载模型的其余字段一样),其中我只想在中间表中创建一个条目,而不是在Load表中创建一个新条目。
因此,就我的项目而言,一个负载可以放在许多容器上,假设它是分开的,因为它不能全部安装在一个容器上,而一个容器可以属于多个负载。
我的models.py看起来是这样的:
class ContainerLoad(models.Model):
    id = models.AutoField(primary_key=True)
    load_number = models.ForeignKey(Load,on_delete=models.CASCADE)
    container_number = models.ForeignKey(Container,on_delete=models.CASCADE)
    pallets = models.CharField(blank=True,null=True,default=0,max_length=20)
    class Meta:
        db_table = 'ContainerLoad'
#load model shortened for brevity
class Load(models.Model):
    id = models.AutoField(primary_key=True)
    bnsf_container_number = models.ManyToManyField(Container, through='ContainerLoad',through_fields=('load_number','container_number'))
    class Meta:
        db_table = "Load"
class Container(models.Model):
    id = models.AutoField(primary_key=True)
    container_number = models.CharField(max_length=15)
    in_use = models.BooleanField()
    
    class Meta:
        db_table = "Container"我的serializers.py现在看起来是这样的,注释掉的部分是我试图让这个帖子开始工作的)
class ContainerLoadSerializer(WritableNestedModelSerializer):
    # load_number_id = LoadSerializer(read_only=False)
    # container_number_id = ContainerSerializer(read_only=False)
    class Meta:
        model = ContainerLoad
        fields = "__all__"
        depth = 2
class LoadSerializer(WritableNestedModelSerializer):
    primary_driver = DriverSerializer(read_only=False)
    second_driver = DriverSerializer(allow_null=True,read_only=False)
    third_driver = DriverSerializer(allow_null=True,read_only=False)
    bnsf_container_number = ContainerSerializer(read_only=False)
    pickup_location = LocationSerializer(read_only=False)
    delivery_location = LocationSerializer(read_only=False)
    broker = BrokerSerializer(read_only=False)
    booked_by = EmployeeSerializer(read_only=False) 
    class Meta:
        model = Load
        fields = '__all__'
        depth = 1
class ContainerSerializer(serializers.ModelSerializer):
    container_number = serializers.CharField()
    in_use = serializers.BooleanField()
    class Meta:
        model = Container
        fields = '__all__'
        depth = 1最后是views.py
class ContainerLoadViews(APIView):
    def get(self, request, id=None):
        if id:
            container = ContainerLoad.objects.get(id=id)
            serializer = ContainerLoadSerializer(container)
            return Response({"status": "success", "data": serializer.data}, status=status.HTTP_200_OK)
        else:
            containers = ContainerLoad.objects.all()
            serializer = ContainerLoadSerializer(containers, many=True)
            return Response({"status": "success", "data": serializer.data}, status=status.HTTP_200_OK)
    
    def post(self, request):
        serializer = ContainerLoadSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({"status": "success", "data": serializer.data}, status=status.HTTP_200_OK)
        else:
            return Response({"status": "Error", "data": serializer.errors}, status=status.HTTP_400_BAD_REQUEST)发布于 2022-08-10 05:01:25
解决这个问题的方法是,当从ContainerLoad表读取数据时,我需要一个嵌套的响应,但是在POSTing数据时需要一个简单的写(而不是嵌套)函数。
解决方案是使用DRF中可用的to_representation和to_internal_value方法(https://www.django-rest-framework.org/api-guide/serializers/#overriding-serialization-and-deserialization-behavior)来覆盖序列化程序的行为。下面是现在适用于GET和POST请求的代码,在插入数据时,它不再向我询问与Load或Container相关的字段。
class ContainerSerializer(serializers.ModelSerializer):
    container_number = serializers.CharField()
    in_use = serializers.BooleanField()
    class ContainerFieldSerializer(serializers.Field):
        def to_internal_value(self,value):
            return Container.objects.get(id=value)
        
        def to_representation(self,instance):
            return ContainerSerializer(instance=instance).data
    class Meta:
        model = Container
        fields = '__all__'
        depth = 1我对负载序列化程序也做了同样的操作。
然后,对于我的ContainerLoad序列化程序,我只将FK字段分配给我创建的新类:
class ContainerLoadSerializer(serializers.ModelSerializer):
    cl_container = ContainerSerializer.ContainerFieldSerializer()
    cl_load = LoadSerializer.LoadFieldSerializer()
    class Meta:
        model = ContainerLoad
        fields = "__all__"
        depth = 2发布于 2022-08-08 05:09:37
如果您查看BaseSerializer类的save方法的代码,您将看到以下内容:
if self.instance is not None:
    self.instance = self.update(self.instance, validated_data)
    assert self.instance is not None, (
        '`update()` did not return an object instance.'
    )
else:
    self.instance = self.create(validated_data)
    assert self.instance is not None, (
        '`create()` did not return an object instance.'
    )如何没有在post函数中传递instance:
serializer = ContainerLoadSerializer(data=request.data)保存总是调用创建。你应该做些类似的事情。
try:
    instance = ContainerLoad.object.get(id=request.data['id'])
except: 
    instance = None
serializer = ContainerLoadSerializer(instance=instance, data = request.data)发布于 2022-08-10 01:00:03
在您的depth元类中,ContainerLoadSerializer设置为2,这告诉序列化程序生成模型的嵌套表示。
https://www.django-rest-framework.org/api-guide/serializers/#specifying-nested-serialization
默认的ModelSerializer为关系使用主键,但也可以使用深度选项轻松地生成嵌套表示: 深度选项应该设置为一个整数值,该值指示在还原到平面表示之前应该遍历的关系的深度。
如果您移除深度属性,序列化程序应该默认返回到期望主键值,这是您想要的行为。
序列化程序应该如下所示:
class ContainerLoadSerializer(serializers.ModelSerializer):
    class Meta:
        model = ContainerLoad
        fields = "__all__"https://stackoverflow.com/questions/73272802
复制相似问题