如何在 Django Rest Framework 中处理并行 PUT/PATCH 请求? (覆盖问题)

How to handle parallel PUT/PATCH requests in Django Rest Framework? (Overwrite issue)

我正在为一个 uni 项目开发一个 Web 应用程序,它是关于机场和承运人的...

问题

问题是当我尝试以并行方式输入数据库时​​,因为在我用作参考的 json 文件中有很多关于承运人和机场的条目.

当您以顺序方式逐个更新(PUT 和 PATCH)时,它可以正常工作,但是当我尝试 PUT/PATCH 并行请求时,数据库中的实例每次都被覆盖。

每个机场都有一个承运人列表,当我尝试通过 PUT 或 PATCH 以并行方式向该列表添加更多承运人时,它会覆盖之前的承运人列表实例

我的模型是:

class Carrier(models.Model):
    code = models.CharField(max_length=10, primary_key=True)
    name = models.TextField()

    def __str__(self):
        return self.name

class Airport(models.Model):
    code = models.CharField(max_length=10, primary_key=True)
    name = models.TextField()
    carriers = models.ManyToManyField(Carrier, related_name='airports')

    def __str__(self):
        return self.name

序列化程序:

class AirportListSerializer(serializers.ModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name='airport-detail')

    class Meta:
        model = models.Airport
        fields = ('code', 'name', 'url')

class AirportDetailSerializer(serializers.ModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name='airport-detail')

    class Meta:
        model = models.Airport
        fields = ('code', 'name', 'url', 'carriers')

我的更新方法有问题,我不得不重写它,因为要将新数据附加到机场实例的运营商数组:

def update(self, request, *args, **kwargs):
        instance = self.get_object()

        serializer = serializers.AirportDetailSerializer(
            instance=instance,
            data=request.data,
            context={'request': request}
        )

        if serializer.is_valid(raise_exception=True):
            # Getting the user inputed carriers after it was validated by the serializer
            carriers = set(dict(request.data)['carriers'])    
            # Adding new carriers to the current airport list of carriers without deleting the old ones
            for carrier in serializer.validated_data['carriers']:
                print(carrier)
                carriers.add(carrier)
            print('Carriers %s' % carriers)
            # Saving alterations to the db
            serializer.save(carriers=carriers)

        # Overriding the original data for more features
        data = serializer.data
        # Creating the carrier links 
        data['carriers'] = ['http://%s/api/carriers/%s/' % (request.get_host(), carrier) for carrier in data['carriers']]

        return Response(data)

DRF 可浏览条目示例 API:

每次您调用 serializer.save(carriers=carriers) 时,您都在保存 Airport 实例,其中仅包含来自您特定 PUT/PATCH 请求的运营商...而不是将运营商添加到您的 Airport实例。

您应该查看 writable nested serializers 的文档并使用单独的 CarrierSerializer

在相关说明中,您的 update 逻辑更适合作为 AirportSerializer 的一部分,而不是您的观点。这使它更具可重用性。 DRF 文档的那部分是您的完美示例。

从 Albums/Tracks 示例改编而来的类似于此伪代码的内容:

class AirportSerializer(serializers.ModelSerializer):
    carriers = CarrierSerializer(many=True)

    class Meta:
        model = Airport
        fields = ......

    def update(self, instance, validated_data):
        carriers_data = validated_data.pop('carriers')
        for carrier in carriers_data:
            Carrier.objects.update_or_create(airport=instance, defaults=carrier_data)
        return instance