3

Try to serialize this Models

Model:

    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

Serializers:

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   

View:

@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)

I need to get data by 1 packet, and then write data in DB

EveryTime I get a error: deliverys_data = validated_data.pop('delivery') KeyError: 'delivery'

Example of JSON packet [{"delivery":{"delivery_time":"2016-05-31T12:18:47Z","delivery_adress":"123","phone":"123"},"paymentMethod":{"id":1,"title":"123124123"},"summ":"23","success":false}]

Weit
  • 571
  • 1
  • 6
  • 20

2 Answers2

0

EveryTime I get a error: deliverys_data = validated_data.pop('delivery') KeyError: 'delivery'

This is to be expected since the OrderSerialzier has DeliverySerializer flagged as read_only. If you want to get the data writable, you'll need to remove that flag first.

Linovia
  • 19,812
  • 4
  • 47
  • 48
  • Without it I get: "non_field_errors": [ "Invalid data. Expected a dictionary, but got list." ] – Weit Jun 07 '16 at 12:36
  • The error you mention should also happen with DeliverySerializer set to read_only. You expect a single Order and send JSON for a list of orders. – Linovia Jun 07 '16 at 13:47
0

You are getting KeyError: 'delivery' because you have set delivery field as read_only. If DRF finds this field in the input, it will ignore that field.

From docs on read_only argument:

Read-only fields are included in the API output, but should not be included in the input during create or update operations. Any 'read_only' fields that are incorrectly included in the serializer input will be ignored.

Also, since you are using paymentMethod field in the create() method, you need to tell DRF to consider that field also in the input.

So, you need to remove the read_only argument from your serializer for both delivery and paymentMethod fields so that these fields are considered when deserializing.

class OrderSerializer(serializers.ModelSerializer):

    delivery = DeliverySerializer() # remove read_only argument
    paymentMethod = PaymentsSerializer() # remove read_only argument

Secondly, you are sending the data incorrectly. You need to send a single order input instead of list of orders you are sending.

# 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}
Rahul Gupta
  • 46,769
  • 10
  • 112
  • 126
  • just removed "read_only", and send correct json, and now I get code 500 with return Database.Cursor.execute(self, query, params) IntegrityError: order_order.delivery_id may not be NULL – Weit Jun 08 '16 at 14:46
  • This is because you are creating `Order` first without creating `Delivery`. As per your model, you should first create `Delivery` and then use that to create `Order` by passing created `delivery` to it. – Rahul Gupta Jun 08 '16 at 15:16
  • but in example http://www.django-rest-framework.org/api-guide/relations/ def create(self, validated_data): tracks_data = validated_data.pop('tracks') album = Album.objects.create(**validated_data) for track_data in tracks_data: Track.objects.create(album=album, **track_data) return album they first of all - make album – Weit Jun 08 '16 at 15:33
  • Yes, they create `Album` first and then `Track` because `Album` is FK to `Track`. Similarly, you should create `Delivery` first and then `Order` because `Delivery` is FK to `Order`. – Rahul Gupta Jun 08 '16 at 16:23
  • http://stackoverflow.com/questions/33205045/create-argument-after-must-be-a-mapping-not-unicode Find another 1 example – Weit Jun 09 '16 at 08:44
  • @Weit I think it would be better that maybe you create another question for solving this error. You should post the complete traceback there with the code you are trying. Also, you can accept this ans if this solved your current question. – Rahul Gupta Jun 09 '16 at 09:27
  • 1
    Thanks, you really solved my current problem. About question in comment - it solved in anothre question: http://stackoverflow.com/questions/37721134/how-to-serialize-relation/37725480#37725480 – Weit Jun 09 '16 at 15:56