我希望能够将具有相关对象数组的模型发布到模型,但是我不知道该怎么做。现在,我能够从这些关系中检索信息,但是不知道如何发布。
Django == 2.2.4 django-rest-framework == 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
最近是我的urls.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()),
]
一切正常,除了URL的POST方法:'api / v1 / pedido / novo'
要发布才能做什么:
{
"cliente": 1,
"produtos":[
{"produto":1, "preco": 5000.00, "quantidade": 3},
{"produto":3, "preco": 4000.00, "quantidade": 4}
]
}
我是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界面上,单击OPTIONS,我看到了:
{
"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
}
}
}
}
}
}
}
仍然在界面中,在RAW数据中,我得到以下信息:
{
"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'
我尝试打印“ validated_data”,但不知道如何。使用pprint不会发生任何事情。
有人吗?好吗?
答案 0 :(得分:-1)
您需要在视图中设置Many = True。告诉序列化程序您可能正在发送序列化列表。 您需要在视图中覆盖get_serializer。
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)