【问题标题】:How to serialize relationship in django rest?如何在 django rest 中序列化关系?
【发布时间】:2016-10-07 00:22:58
【问题描述】:

尝试序列化这个模型

型号:

    class Order (models.Model):
        id = models.AutoField(primary_key=True)
        date_create = models.DateField(auto_now_add=True)
        date_change = models.DateField(auto_now=True)
        summ =models.CharField(max_length=15,default='0')
        delivery = models.ForeignKey('Delivery')
        success = models.BooleanField(default=False)
        paymentMethod = models.ForeignKey('Payments')
        def __unicode__(self):
            return unicode(self.id)

    class OrderProduct(models.Model):
        order=models.ForeignKey('Order')
        id = models.AutoField(primary_key=True)
        date_create = models.DateField(auto_now_add=True)
        date_change = models.DateField(auto_now=True)
        price = models.IntegerField()
        product = models.ForeignKey('product.Product')
        additionals = models.IntegerField(null=True,default=0)
        count = models.IntegerField()
        def __unicode__(self):
                return self.id


    class Delivery(models.Model):
        id = models.AutoField(primary_key=True)
        date_create = models.DateField(auto_now_add=True)
        date_change = models.DateField(auto_now=True)
        delivery_time = models.DateTimeField()
        delivery_adress = models.TextField()
        phone = models.TextField()
        def __unicode__(self):
                return self.phone

    class Payments(models.Model):
        id = models.AutoField(primary_key=True)
        date_create = models.DateField(auto_now_add=True)
        date_change = models.DateField(auto_now=True)
        title = models.TextField();
        def __unicode__(self):
                return self.title

序列化器:

class DeliverySerializer(serializers.ModelSerializer):
    class Meta:
        model = Delivery
        fields = ('id', 'delivery_time','delivery_adress','phone')
    def create(self, validated_data):
        return Delivery.objects.create(**validated_data)   


class PaymentsSerializer(serializers.ModelSerializer):
    class Meta:
        model = Payments
        fields = ('id', 'title')
    def create(self, validated_data):
        return Payments.objects.create(**validated_data)   



class OrderSerializer(serializers.ModelSerializer):

    delivery = DeliverySerializer(read_only=True)
    paymentMethod = PaymentsSerializer(read_only=True)
    class Meta:
        model = Order
        fields = ('id', 'delivery', 'paymentMethod','summ','success') 

    def create(self, validated_data):
        deliverys_data = validated_data.pop('delivery')
        paymentsMethod_data = validated_data.pop('paymentMethod')
        order = Order.objects.create(**validated_data)
        for delivery_data in deliverys_data:
            Delivery.objects.create(order=order, **delivery_data)
        for paymentMethod_data in paymentsMethod_data:
            Payments.objects.create(order=order, **paymentMethod_data)
        return order   

查看:

@api_view(['POST'])
def order_post(request, format=None):

   #List all snippets, or create a new snippet.

    if request.method == 'POST':
        serializer = OrderSerializer(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)

我需要通过1个数据包获取数据,然后在DB中写入数据

每次我得到一个错误: Deliverys_data = valid_data.pop('delivery') KeyError:'交付'

JSON 数据包示例 [{"delivery":{"delivery_time":"2016-05-31T12:18:47Z","delivery_adress":"123","phone":"123"},"paymentMethod":{"id":1 ,"title":"123124123"},"summ":"23","success":false}]

【问题讨论】:

    标签: json django django-models django-rest-framework


    【解决方案1】:

    您将获得KeyError: 'delivery',因为您已将delivery 字段设置为read_only。如果 DRF 在输入中找到该字段,它将忽略该字段。

    来自read_only argument:上的文档

    API 输出中包含只读字段,但不应包含 在创建或更新操作期间包含在输入中。任何 'read_only' 序列化程序中错误包含的字段 输入将被忽略。

    此外,由于您在 create() 方法中使用了 paymentMethod 字段,因此您需要告诉 DRF 在输入中也考虑该字段。

    因此,您需要从序列化程序中删除 deliverypaymentMethod 字段的 read_only 参数,以便在反序列化时考虑这些字段。

    class OrderSerializer(serializers.ModelSerializer):
    
        delivery = DeliverySerializer() # remove read_only argument
        paymentMethod = PaymentsSerializer() # remove read_only argument
    

    其次,您发送的数据不正确。您需要发送单个 order 输入,而不是发送的订单列表。

    # send without the list 
    {"delivery":{"delivery_time":"2016-05-31T12:18:47Z","delivery_adress":"123","phone":"123"},"paymentMethod":{"id":1,"title":"123124123"},"summ":"23","success":false}
    

    【讨论】:

    • 刚刚删除“read_only”,并发送正确的 json,现在我得到代码 500,返回 Database.Cursor.execute(self, query, params) IntegrityError: order_order.delivery_id may not be NULL跨度>
    • 这是因为您先创建Order 而没有创建Delivery。根据您的模型,您应该首先创建Delivery,然后通过将创建的delivery 传递给它来使用它来创建Order
    • 但在示例中 django-rest-framework.org/api-guide/relations def create(self,validated_data): tracking_data = valid_data.pop('tracks') album = Album.objects.create(**validated_data) for track_data in tracking_data: Track .objects.create(album=album, **track_data) 他们首先返回专辑 - 制作专辑
    • 是的,他们先创建Album,然后再创建Track,因为AlbumTrack 的FK。同样,您应该先创建Delivery,然后再创建Order,因为DeliveryOrder 的FK。
    • 谢谢,你真的解决了我目前的问题。关于评论中的问题 - 它解决了另一个问题:stackoverflow.com/questions/37721134/how-to-serialize-relation/…
    【解决方案2】:

    每次我得到一个错误:deliverys_data = valid_data.pop('delivery') KeyError: 'delivery'

    这是意料之中的,因为 OrderSerialzier 已将 DeliverySerializer 标记为 read_only。 如果你想让数据可写,你需要先删除那个标志。

    【讨论】:

    • 没有它我得到:“non_field_errors”:[“无效数据。需要字典,但得到了列表。” ]
    • 您提到的错误也应该在 DeliverySerializer 设置为 read_only 时发生。您期望一个订单并为订单列表发送 JSON。
    猜你喜欢
    • 2014-02-02
    • 2015-12-13
    • 2015-03-04
    • 2016-12-18
    • 2017-10-05
    • 1970-01-01
    • 1970-01-01
    • 2021-06-12
    • 1970-01-01
    相关资源
    最近更新 更多