Django Rest框架-如何设置序列化程序以使用相关模型创建ApiView
我希望能够发布到具有相关对象数组的模型,但我不知道如何发布。现在我可以从这些关系中检索信息,但不知道如何发布 Django==2.2.4 django rest框架==3.10.3 models.pyDjango 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
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)