首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >DRF中间表-到中间表的POSTing数据

DRF中间表-到中间表的POSTing数据
EN

Stack Overflow用户
提问于 2022-08-08 03:58:51
回答 3查看 43关注 0票数 1

在我的DB设计中,我有一个多到多的关系,我在POST方面遇到了麻烦。我目前有一个名为Load、Containers和Container_Loads的表(这是中间表)。

我的问题是:我希望能够向ContainerLoad中间表发送一个POST请求,并使用它所需的值更新该表,这些值是: Load ID ( Load表的PK)、Container (容器表的PK)和#的托盘(中间表的唯一字段)。我能够很好地获取/检索记录,但是当我试图发送带有有效负载的POST请求时,例如

代码语言:javascript
运行
复制
{
        "id":3,
        "pallets":"4",
        "containerNumberId":5,
        "loadNumberId":53
}

(其中containerNumberID和loadNumberID是各自表中的现有键),我的代码似乎也希望创建一个全新的加载条目(正如它向我请求加载模型的其余字段一样),其中我只想在中间表中创建一个条目,而不是在Load表中创建一个新条目。

因此,就我的项目而言,一个负载可以放在许多容器上,假设它是分开的,因为它不能全部安装在一个容器上,而一个容器可以属于多个负载。

我的models.py看起来是这样的:

代码语言:javascript
运行
复制
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现在看起来是这样的,注释掉的部分是我试图让这个帖子开始工作的)

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
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)
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 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相关的字段。

代码语言:javascript
运行
复制
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字段分配给我创建的新类:

代码语言:javascript
运行
复制
class ContainerLoadSerializer(serializers.ModelSerializer):

    cl_container = ContainerSerializer.ContainerFieldSerializer()
    cl_load = LoadSerializer.LoadFieldSerializer()

    class Meta:
        model = ContainerLoad
        fields = "__all__"
        depth = 2
票数 0
EN

Stack Overflow用户

发布于 2022-08-08 05:09:37

如果您查看BaseSerializer类的save方法的代码,您将看到以下内容:

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
serializer = ContainerLoadSerializer(data=request.data)

保存总是调用创建。你应该做些类似的事情。

代码语言:javascript
运行
复制
try:
    instance = ContainerLoad.object.get(id=request.data['id'])
except: 
    instance = None

serializer = ContainerLoadSerializer(instance=instance, data = request.data)
票数 0
EN

Stack Overflow用户

发布于 2022-08-10 01:00:03

在您的depth元类中,ContainerLoadSerializer设置为2,这告诉序列化程序生成模型的嵌套表示。

https://www.django-rest-framework.org/api-guide/serializers/#specifying-nested-serialization

默认的ModelSerializer为关系使用主键,但也可以使用深度选项轻松地生成嵌套表示: 深度选项应该设置为一个整数值,该值指示在还原到平面表示之前应该遍历的关系的深度。

如果您移除深度属性,序列化程序应该默认返回到期望主键值,这是您想要的行为。

序列化程序应该如下所示:

代码语言:javascript
运行
复制
class ContainerLoadSerializer(serializers.ModelSerializer):

    class Meta:
        model = ContainerLoad
        fields = "__all__"
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73272802

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档