【问题标题】:DRF - Serializer Multiple ModelsDRF - 串行器多个模型
【发布时间】:2019-07-25 23:44:11
【问题描述】:

我如何发布这个 JSON

{
  "campaign": 27,
  "campaignName": "Prueba promo",
  "promotionType": 999,
  "items": [
     { "item_nbr": 1234567890123, "plu": 2},
     { "item_nbr": 12345678901, "plu": 3}
  ]
}

目前,我只收到此响应 JSON

{
"items": [],
"campaign": 27,
"campaignName": "Prueba promo",
"promotionType": 999,
"start_date": "2019-03-04T12:02:16.574874-03:00",
"end_date": null,
"active": true
}

我该怎么做?我阅读了 DRF 文档,但没有用,我做错了什么? 这是我的代码

我的模型.py

class Item(models.Model):
    promocion = models.ForeignKey(Promocion, related_name='items', on_delete=models.CASCADE, null=True)
    item_nbr = models.IntegerField(primary_key=True, help_text="Numero de Item")
    modular = models.ForeignKey(Modular, on_delete=models.CASCADE, null=True)
    price = models.FloatField()
    q_min = models.PositiveIntegerField(default=1, help_text="Cantidad mínima")
    q_mul = models.PositiveIntegerField(default=1, help_text="Multiplo de cajas cerradas")
    vensil1 = models.CharField(max_length=30, help_text="Atributo item relevante")
    vensil2 = models.CharField(max_length=30, help_text="Atributo item relevante")
    vensil3 = models.CharField(max_length=30, help_text="Atributo item relevante")
    FG = "Fleje grande, 1/3 Carta"
    FP = "Fleje pequeño 1/6 Carta"
    CP = "Carteleria media Carta"
    opciones = ((FG, "Fleje grande, 1/3 Carta"),
                (FP, "Fleje pequeño 1/6 Carta"),
                (CP, "Carteleria media Carta"),)
    print_type = models.CharField(choices=opciones, help_text="Fleje a imprimir", max_length=255)
    depto = models.IntegerField(default=1, help_text="Departamento")
    descri = models.CharField(max_length=100, help_text="Descripción producto")
    brand = models.ForeignKey(Brand, on_delete=models.CASCADE, null=True)
    vendor_pack = models.IntegerField(default=1)
    container = models.CharField(max_length=6, default="MAY")
    size = models.CharField(max_length=20, help_text="Tamaño pack")
    cont_net = models.FloatField(default=1, help_text="Contenido Neto")
    sell_unit = models.CharField(max_length=5, help_text="Unidad de venta")
    weight_drain = models.FloatField(default=0, help_text="Peso drenado")
    cod_bal = models.IntegerField(null=True, blank=True, help_text="Código balanza")
    plu = models.BigIntegerField(help_text="Código de barra")

这是我的 serializer.py

class ItemPromoSerializer(serializers.ModelSerializer):
    class Meta:
        model = Item
        fields = ('item_nbr', 'plu')

class PromoSerializer(serializers.ModelSerializer):
    items = ItemPromoSerializer(many=True, read_only=True)
    #steps = ScalePromoSerializer(many=True)
    class Meta:
         model = Promocion
         fields = ('items', 'campaign', 'campaignName', 'promotionType', 
     'start_date', 'end_date', 'active')

我的viewsets.py

class PromoViewSet(viewsets.ModelViewSet):
    queryset = Promocion.objects.all()
    serializer_class = PromoSerializer

还有我的 routes.py

router.register(r'promo', PromoViewSet)

我尝试了to_internal_value()to_representation()的方法,但结果是

"non_field_errors": ["Invalid data. Expected a dictionary, but got list."]

【问题讨论】:

  • 什么时候出现错误?尝试创建新实例时?
  • 我的错误是当我尝试发布该 json 时
  • 你的 json 有效载荷是什么?
  • 第一个Json是我的payload,第二个是响应
  • 我认为您正在尝试实现Nested Writable Serializer。检查文档

标签: json django python-3.x django-rest-framework deserialization


【解决方案1】:

如果在 POST 请求期间发生此问题,则意味着您需要调整保存数据的方式。 Django REST Framework 不支持开箱即用地在 DB 中写入嵌套对象。

我通常对这些用例做的是

  1. 对于如此复杂的用例,我不使用视图集,而是更喜欢使用 CreateAPIView,它使我能够使用特定的序列化程序来验证输入和呈现数据。
  2. 我挂钩createCreateAPIView 并在同时写入多个表时使用with transaction.atomic(): 以确保所有事务都无效,以防出现错误。
  3. 我使用 2 个序列化程序,一个用于父模型,一个用于子模型。

在你的情况下,代码可能是这样的:

serializer.py

class PromoSerializer(serializers.ModelSerializer):
    class Meta:
        model = Promocion
        fields = ('campaign', 'campaignName', 'promotionType', 'start_date', 'end_date', 'active')

class ItemPromoSerializer(serializers.ModelSerializer):
    class Meta:
        model = Item
        fields = ('item_nbr', 'plu')

viewsets.py

from rest_framework import status
from django.db import transaction

class PromoCreateAPI(CreateAPIView):
    queryset = Promocion.objects.all()
    serializer_class = PromoSerializer

    # We skip perform_create
    def create(self, request, *args, ***kwargs):
        try:
            items_data = request.data.pop('items')
        except KeyError:
            return Response({}, status=status.HTTP_400_BAD_REQUEST)

        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        with transaction.atomic():
            instance = serializer.save()
            # Validate each item
            for item in items_data:
                s = ItemPromoSerializer(data=item)
                s.is_valid(raise_exception=True)
                s.save(campaign=instance)
        headers = self.get_success_headers(serializer.data)
        serializer.data['items'] = items_data
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

当然,这段代码未经测试,但我希望它能帮助你到达你需要的地方。

【讨论】:

    猜你喜欢
    • 2021-02-18
    • 2019-07-22
    • 2018-12-01
    • 1970-01-01
    • 2016-07-17
    • 2018-03-16
    • 2016-02-23
    • 1970-01-01
    • 2021-05-29
    相关资源
    最近更新 更多