带有Django Rest Framework的可写双嵌套序列化器

时间:2016-05-09 10:17:22

标签: django serialization nested django-rest-framework writable

我有1个或多个product_invoice的发票,有些product_invoice可以有1个product_order(因此在ProductOrder中,productinvoiceid应该是OneToOne的关系,但对我的问题并不重要)。

我能够在2级获取数据,但我无法创建,存在此错误:

  

TypeError:'orderinfo'是此函数的无效关键字参数。

但如果我在orderinfo中移除ProductInvoiceSerializer,我就可以创建发票和相关的Product_Invoice

我做错了什么?

django:1.9.3,DRF:3.3.3

[
{
    "invoiceid": 43,
    "stocklocationid": 1,
    "invoicecode": "OBR00040",
    "invoicedate": "2016-05-07",
    "totalamount": 500000,
    "buypricetotal": 125000,
    "discount": 0,
    "ppnamount": 50000,
    "ispaid": true,
    "deposit": 0,
    "emailaddress": "",
    "customername": "",
    "invoicenote": "",
    "isorder": false,
    "deliverydate": null,
    "products": [
        {
            "productinvoiceid": 48,
            "productid": 1,
            "quantity": 1,
            "buyingprice": 200000,
            "saleprice": 100000,
            "orderinfo": [
                {
                    "productorderid": 2,
                    "note": "",
                    "isstock": false,
                    "stocklocationid": 1,
                    "ispickedup": 0
                }
            ]
        }
    ]
},

我的模特:

class Invoice(models.Model):
    invoiceid = models.AutoField(db_column='InvoiceID', primary_key=True)
    invoicecode = models.CharField(db_column='InvoiceCode', unique=True, max_length=8)

    class Meta:
        managed = False
        db_table = 'invoice'

class ProductInvoice(models.Model):
    productinvoiceid = models.AutoField(db_column='ProductInvoiceID', primary_key=True)
    productid = models.ForeignKey(Product, models.DO_NOTHING, db_column='ProductID')
    invoiceid = models.ForeignKey(Invoice, models.DO_NOTHING, db_column='InvoiceID', related_name='products')
    quantity = models.IntegerField(db_column='Quantity', verbose_name='Quantity')

class Meta:
    managed = False
    db_table = 'product_invoice'

class ProductOrder(models.Model):
    productorderid = models.AutoField(db_column='ProductOrderID', primary_key=True)
    productinvoiceid = models.ForeignKey(ProductInvoice, models.DO_NOTHING, db_column='ProductInvoiceID', related_name='orderinfo')
    isstock = models.BooleanField(db_column='Stock', verbose_name = 'Is stock ?')
    isreadytopick = models.IntegerField(db_column='ReadyToPick')
    ispickedup = models.IntegerField(db_column='PickedUp', verbose_name = 'Already picked-up ?')

class Meta:
    managed = False
    db_table = 'product_order'

My Serializer:

class ProductOrderSerializer(serializers.ModelSerializer):
    class Meta:
        model = ProductOrder
        fields = ('productorderid','note','isstock','stocklocationid','ispickedup')

class ProductInvoiceSerializer(serializers.ModelSerializer):
    orderinfo = ProductOrderSerializer(many=True)

    class Meta:
        model = ProductInvoice
        fields = ('productinvoiceid', 'productid', 'quantity', 'buyingprice', 'saleprice', 'orderinfo')
    #fields = ('productinvoiceid', 'productid', 'quantity', 'buyingprice', 'saleprice')

    def create(self, validated_data):
        ordersinfo_data = validated_data.pop('orderinfo')
        product_invoice = ProductInvoice.objects.create(**validated_data)
        for orderinfo_data in ordersinfo_data:
            ProductOrder.objects.create(productinvoiceid=product_invoice, **orderinfo_data)
        return product_invoice

class InvoiceSerializer(serializers.ModelSerializer):
    products = ProductInvoiceSerializer(many=True)

    class Meta:
        model = Invoice
        fields = ('invoiceid', 'stocklocationid', 'invoicecode','invoicedate','totalamount','buypricetotal','discount','ppnamount','ispaid','deposit','emailaddress','customername','invoicenote','isorder','deliverydate','products')

    def create(self, validated_data):
        products_data = validated_data.pop('products')
        invoice = Invoice.objects.create(**validated_data)
        for product_data in products_data:
            #product_data.invoiceid = invoice.invoiceid
            ProductInvoice.objects.create(invoiceid=invoice, **product_data)
        return invoice

更新2016-05-11

view.py

@api_view(['GET', 'POST'])
def invoice_list(request):

if request.method == 'GET':
    invoices = Invoice.objects.all()
    serializer = InvoiceSerializer(invoices, many=True)
    return Response(serializer.data)

elif request.method == 'POST':
    serializer = InvoiceSerializer(data=request.data)
    if serializer.is_valid():
        serializer.save()
        return JSONResponse(serializer.data, status=status.HTTP_201_CREATED, )
    return JSONResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

1 个答案:

答案 0 :(得分:0)

由于您在ProductInvoiceProductInvoice.objects.create(invoiceid=invoice, **product_data)手动创建ProductInvoice对象,因此模型没有任何名为orderinfo的字段。

现在你正在使用

orderinfo = ProductOrderSerializer(many=True)

ProductInvoice需要ManyToMany字段来存储orderinfo

因此你的模型应该是这样的:

class ProductInvoice(models.Model):
    productinvoiceid = models.AutoField(db_column='ProductInvoiceID', primary_key=True)
    productid = models.ForeignKey(Product, models.DO_NOTHING, db_column='ProductID')
    invoiceid = models.ForeignKey(Invoice, models.DO_NOTHING, db_column='InvoiceID', related_name='products')
    quantity = models.IntegerField(db_column='Quantity', verbose_name='Quantity')
    orderinfo = models.ManyToManyField(ProductOrder)

您应该使用ProductInvoiceSerializer创建ProductInvoice对象:

def create(self, validated_data):
        products_data = validated_data.pop('products')
        invoice = Invoice.objects.create(**validated_data)
        for product_data in products_data:
            #product_data.invoiceid = invoice.invoiceid
            data = product_data
            data['invoiceid'] = invoice
            serializer = ProductInvoiceSerializer(data=data)
            if serializer.is_valid(raise_exception=True):
                serializer.save()
        return invoice