DRF - сериализатор нескольких моделей - PullRequest
0 голосов
/ 04 марта 2019

пожалуйста, помогите!Как я могу получить этот 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, но она не сработала, что я делаю не так?вот мой код

мой models.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")

def __str__(self):
    return str(self.item_nbr) + ' - ' + str(self.plu)

class Promocion(models.Model):
    campaign = models.ForeignKey(Campaign, on_delete=models.CASCADE, null=True)
    campaignName = models.CharField(max_length=50, null=True)
    promotionType = models.IntegerField()
    priority = models.IntegerField(default=1)
    start_date = models.DateTimeField(default=timezone.now, help_text="Fecha 
 inicio promoción")
    end_date = models.DateTimeField(null=True, blank=True, help_text="Fecha 
 fin promoción")
    active = models.BooleanField(default=True)

вот мой 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

и мои route.py

router.register(r'promo', PromoViewSet)

Пожалуйста, помогите мне!Я стек, я пытаюсь сделать to_internal_value () и to_representation (), но он отвечает мне "non_field_errors": ["Неверные данные. Ожидается словарь, но есть список."]

Переслать спасибо всем!

1 Ответ

0 голосов
/ 05 марта 2019

Если эта проблема возникает во время запроса POST, это означает, что вам нужно адаптировать способ сохранения ваших данных.Django REST Framework не поддерживает запись вложенных объектов в БД из коробки.

Что я обычно делаю для этих случаев использования, это

  1. Я не использую viewset для таких сложныхвместо этого я предпочитаю использовать CreateAPIView, что позволяет мне использовать определенные сериализаторы для проверки входных данных и представления данных.
  2. Я подключаю create из CreateAPIView и использую 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)

Конечно, этот код не проверен, но я надеюсь, что онпоможет вам добраться туда, куда вам нужно.

...