Django Rest框架-如何设置序列化程序以使用相关模型创建ApiView

Django Rest框架-如何设置序列化程序以使用相关模型创建ApiView,django,django-rest-framework,Django,Django Rest Framework,我希望能够发布到具有相关对象数组的模型,但我不知道如何发布。现在我可以从这些关系中检索信息,但不知道如何发布 Django==2.2.4 django rest框架==3.10.3 models.py from django.db import models import datetime from django.utils.html import format_html_join from collections import Counter class Cliente(models.Mo

我希望能够发布到具有相关对象数组的模型,但我不知道如何发布。现在我可以从这些关系中检索信息,但不知道如何发布

Django==2.2.4 django rest框架==3.10.3

models.py

from django.db import models
import datetime
from django.utils.html import format_html_join

from collections import Counter

class Cliente(models.Model):
    def __str__(self):
        return self.nome
    nome = models.CharField(max_length=200)

    class Meta:
        ordering = ['id']

class Produto(models.Model):
    def __str__(self):
        return self.nome + ", Preço unitário: " + str(self.preco_unitario)

    nome = models.CharField(max_length=200)
    preco_unitario = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)
    multiplo = models.IntegerField(blank=True, null=True)

class Pedido(models.Model):

    cliente = models.ForeignKey(Cliente, models.DO_NOTHING, null=True, blank=True)
    created = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return '%s' % (self.pedido_id)

    def total(self):
        itens = ItensPedido.objects.filter(pedido=self.pk)
        valor = sum(Counter(item.preco * item.quantidade for item in itens))
        return str(valor)

class ItensPedido(models.Model):

    pedido = models.ForeignKey(Pedido, on_delete=models.CASCADE,related_name='itemspedido', null=True)
    produto = models.ForeignKey(Produto, on_delete=models.CASCADE, null=True)
    preco = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)
    quantidade = models.IntegerField(default=1, null=False)
    created = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.pedido.pedido_id + ": " + self.produto.nome + ", preço: " + str(self.preco) + ", quantidade: " + str(self.quantidade)


然后我有了我的serializers.py

from .models import Produto, Cliente, Pedido, ItensPedido
from rest_framework import serializers

class ProdutoSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    nome = serializers.CharField()
    preco_unitario = serializers.DecimalField(min_value=0.01, decimal_places=2, max_digits=None, coerce_to_string=False)
    multiplo = serializers.IntegerField()
    class Meta:
        model=Produto
        fields=('id', 'nome', 'preco_unitario', 'multiplo')

class ClienteSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    nome = serializers.CharField()
    class Meta:
        model=Cliente
        fields=('id', 'nome')

class ItensPedidoSerializer(serializers.ModelSerializer):
    produto = serializers.CharField(source='produto.nome')
    preco = serializers.DecimalField(min_value=0.01, decimal_places=2, max_digits=None, coerce_to_string=False)
    quantidade = serializers.IntegerField()

    class Meta:
        model=ItensPedido
        fields=('produto', 'preco', 'quantidade')

class PedidoSerializer(serializers.ModelSerializer):
    cliente = serializers.CharField(source='cliente.nome')
    produtos = serializers.SerializerMethodField()
    total = serializers.DecimalField(max_digits=None, decimal_places=2, read_only=True, coerce_to_string=False)

    class Meta:
        model=Pedido
        fields=('id', 'cliente', 'total', 'produtos')

    def get_produtos(self, instance):
        items = ItensPedido.objects.filter(pedido=instance)
        return ItensPedidoSerializer(items, many=True).data

    def create(self, validated_data):
        cliente_id = validated_data.pop('cliente')
        produtos_dados = validated_data.pop('produtos')
        pedido = Pedido.objects.create(cliente=cliente_id, **validated_data)
        for produto_dados in produtos_dados:
            ItensPedido.objects.create(pedido=pedido, **produto_dados)
        return pedido


还有我的api_views.py

from rest_framework.generics import ListAPIView, CreateAPIView, RetrieveAPIView
from rest_framework.exceptions import ValidationError
from api.serializers import ProdutoSerializer, ClienteSerializer, PedidoSerializer
from api.models import Produto, Cliente, Pedido

class ListaProdutos(ListAPIView):
    queryset = Produto.objects.all()
    serializer_class = ProdutoSerializer

class ListaClientes(ListAPIView):
    queryset = Cliente.objects.all()
    serializer_class = ClienteSerializer

class ListaPedidos(ListAPIView):
    queryset = Pedido.objects.all()
    serializer_class = PedidoSerializer

class ListaPedido(RetrieveAPIView):
    queryset = Pedido.objects.all()
    serializer_class = PedidoSerializer
    lookup_field = 'id'


class CriaPedido(CreateAPIView):
    serializer_class = PedidoSerializer

最后,我的URL.py:

urlpatterns = [
    path('api/v1/produtos/', api.api_views.ListaProdutos.as_view()),
    path('api/v1/clientes/', api.api_views.ListaClientes.as_view()),
    path('api/v1/pedidos/', api.api_views.ListaPedidos.as_view()),
    path('api/v1/pedido/novo', api.api_views.CriaPedido.as_view()),
    path('api/v1/pedido/<int:id>/', api.api_views.ListaPedido.as_view()),
]
我是DRF的新手。谢谢你的帮助

更新日期:2019-09-13

我对代码做了一点修改,但得到了相同的错误

我已经创建了另一个序列化程序来创建模型:

class CriaPedidoSerializer(PedidoSerializer):
    produtos = ItensPedidoSerializer(many=True)

    def create(self, validated_data):
        produtos_dados = validated_data.pop('produtos')
        pedido = Pedido.objects.create(**validated_data)
        for produto_dados in produtos_dados:
            ItensPedido.objects.create(pedido=pedido, **produto_dados)
        return pedido
我认为:

class CriaPedido(CreateAPIView):
    serializer_class = CriaPedidoSerializer

    def create(self, request, *args, **kwargs):
        try: 
            cliente = request.data.get('cliente')
            if not cliente:
                raise ValidationError({'cliente': 'É necessário um cliente para realizar um pedido!'})
        except ValueError:
            raise ValidationError({'cliente': 'Deve ser um cliente já cadastrado!'})
        return super().create(self, request, *args, **kwargs)
在DRF界面,单击选项,我看到:

{
    "name": "Cria Pedido",
    "description": "",
    "renders": [
        "application/json",
        "text/html"
    ],
    "parses": [
        "application/json",
        "application/x-www-form-urlencoded",
        "multipart/form-data"
    ],
    "actions": {
        "POST": {
            "id": {
                "type": "integer",
                "required": false,
                "read_only": true,
                "label": "ID"
            },
            "cliente": {
                "type": "field",
                "required": true,
                "read_only": false,
                "label": "Cliente"
            },
            "total": {
                "type": "string",
                "required": false,
                "read_only": true,
                "label": "Total",
                "min_length": 2,
                "max_length": 30
            },
            "produtos": {
                "type": "field",
                "required": true,
                "read_only": false,
                "label": "Produtos",
                "child": {
                    "type": "nested object",
                    "required": true,
                    "read_only": false,
                    "children": {
                        "id": {
                            "type": "integer",
                            "required": false,
                            "read_only": true,
                            "label": "ID"
                        },
                        "produto": {
                            "type": "field",
                            "required": true,
                            "read_only": false,
                            "label": "Produto"
                        },
                        "preco": {
                            "type": "decimal",
                            "required": false,
                            "read_only": false,
                            "label": "Preco"
                        },
                        "quantidade": {
                            "type": "integer",
                            "required": false,
                            "read_only": false,
                            "label": "Quantidade",
                            "min_value": -2147483648,
                            "max_value": 2147483647
                        }
                    }
                }
            }
        }
    }
}
仍然在界面中,在原始数据中我得到:

{
    "cliente": null,
    "produtos": []
}
但当我尝试发布时:

{
            "cliente": 1,
            "produtos":[
                {"produto":1, "preco": 5000.00, "quantidade": 3},
                {"produto":3, "preco": 4000.00, "quantidade": 4}
            ]

        }
我收到错误消息:

“CriaPedido”对象没有属性“data”

更新-仍为2019-09-13-------------------

问题似乎出在我的CriaPedidoSerializer下的create方法上,经过几次更改后如下所示:

class CriaPedidoSerializer(serializers.ModelSerializer):
    cliente = serializers.PrimaryKeyRelatedField(many=False, queryset=Cliente.objects.all())
    produtos = ItensPedidoSerializer(many=True)

    class Meta:
        model=Pedido
        fields=('id', 'cliente', 'total', 'produtos') 
        ready_only_fields=('id',)

    def create(self, validated_data):
        cliente_dados = validated_data['cliente']
        produtos_dados = validated_data['produtos']
        pedido, created = Pedido.objects.get_or_create(cliente=cliente_dados)
        for produto_dados in produtos_dados:
            ItensPedido.objects.create(pedido=pedido.id, **produto_dados)
        return pedido
仍然会出现相同的错误:“CriaPedido”对象没有“data”属性

我试图打印“已验证的数据”,但不知道如何打印。使用pprint不会发生任何事情


有人吗?请?

您需要在视图中设置Many=True。告诉序列化程序您可能正在发送序列化列表。 您需要在视图中覆盖get_序列化程序

class YourAPIView(viewsets.ModelViewSet):


    def get_serializer(self, *args, **kwargs):
        if "data" in kwargs:
            data = kwargs["data"]

            # check if many is required
            if isinstance(data, list):
                kwargs["many"] = True

        return super(YourAPIView, self).get_serializer(*args, **kwargs)

显示的错误信息是什么?@RudolfOlah我已经更新了问题。错误为:“CriaPedido”对象没有“data”属性
class YourAPIView(viewsets.ModelViewSet):


    def get_serializer(self, *args, **kwargs):
        if "data" in kwargs:
            data = kwargs["data"]

            # check if many is required
            if isinstance(data, list):
                kwargs["many"] = True

        return super(YourAPIView, self).get_serializer(*args, **kwargs)