我正在尝试在Django中制作一个简单的比萨订购应用程序。我有3个模型(浇头,比萨饼,订单)。在订单模型中,ManyToManyField为Pizza。如果“用户”订购每个比萨饼一个(例如,玛格丽塔和意大利辣香肠),则工作正常,但是如果在POST请求中订购2个玛格丽塔,则结果中只有一个玛格丽塔ID。我如何在一个订单中传递正宗披萨?
我的模型如下:
class Toppings(models.Model):
name = models.CharField(blank=False, max_length=100, unique=True)
class Meta:
ordering = ['name']
def __str__(self):
return self.name
class Pizza(models.Model):
name = models.CharField(blank=False, max_length=100, unique=True)
ingredients = models.ManyToManyField(Toppings, blank=False, null=False)
class Meta:
ordering = ['name']
def __str__(self):
return self.name
class PizzaOrder(models.Model):
created = models.DateTimeField(auto_now_add=True)
items = models.ManyToManyField(Pizza, blank=False, null=False)
status = models.CharField(max_length=1, choices=[
(1, 'placed'),
(2, 'approved'),
(3, 'cooked'),
(4, 'delivered'),
(5, 'canceled')
], default=1)
class Meta:
ordering = ['created']
def __str__(self):
return self.created
我使用此数据发送POST:
{
"items": [1, 1, 1, 2, 2],
"status": 1
}
并且仅在项目列表中得到了这个1和2(不是1,1,1,2,2):
{
"id": 2,
"items": [
1,
2
],
"status": 1
}
序列化器和订单视图
class OrdersSerializer(serializers.ModelSerializer):
class Meta:
model = PizzaOrder
fields = ['id', 'items', 'status', 'created']
class PizzaOrdersList(ModelViewSet):
queryset = PizzaOrder.objects.all()
serializer_class = OrdersSerializer
直通模型对此非常适合。 ManyToManyFields
在后台创建这种数据库关系,它仅创建Pizza和PizzaOrder的唯一组合,但是您可以自己轻松实现它。
简单地创建一个名为PizzaOrderItem
的类,其中包含Pizza和PizzaOrder模型的ForeignKeys
:
class PizzaOrderItem(models.Model):
pizza = ForeignKey(Pizza)
pizza_order = ForeignKey(PizzaOrder)
然后您可以更改ManyToManyField以使用通过模型创建的自定义:
class PizzaOrder(models.Model):
...
items = models.ManyToManyField(Pizza, through='<your_app_name>.PizzaOrderItem',
blank=False,
null=False)
...
您甚至可以将额外的字段(例如浇头或数量)添加到贯通模型中,如下所示:
class PizzaOrderItem(models.Model):
pizza = ForeignKey(Pizza)
pizza_order = ForeignKey(PizzaOrder)
toppings = ManyToManyField(Toppings)
quantity = IntegerField(default=1)
您可以通过order.items
依次访问披萨,并通过order.pizza_order_item_set
依次访问模型对象。
序列化器
检索订单的商品非常简单。为了正确显示新的PizzaOrderItems
,您需要添加一个序列化器,并在PizzaOrderSerializer
上设置项目以使用新的序列化器:
class PizzaOrderItemSerializer(serializer.ModelSerializer):
class Meta:
model = AuthorsOrder
# If you add a field like quantity you can add them to the fields list below.
fields = ['pizza', 'pizza_order']
class PizzaOrderSerializer(serializer.ModelSerializer):
items = PizzaOrderItemSerializer(source='pizza_order_item_set', many=True)
class Meta:
model = PizzaOrder
fields = ['id', 'items', 'status', 'created']
创建PizzaOrderItems
有两种创建PizzaOrderItems的方法。第一个非常简单。只需创建类似于PizzaOrder
的视图,然后使用PizzaOrderItemSerializer
:
class PizzaOrderItemViewSet(generics.ListCreateAPIView):
queryset = PizzaOrderItem.objects.all()
serializer_class = PizzaOrderItemSerializer
然后您可以使用POST数据为订单创建商品:
{
"pizza" : <pizza_id_here>
"pizza_order" : <pizza_order_id_here>
}
第二种方法是仅使用PizzaOrder视图,并将create函数覆盖到PizzaOrder序列化程序。这是因为嵌套的序列化程序默认情况下是只读的,因此我们在这里要做的是重写根序列化程序的create方法,并使用嵌套的序列化程序的已验证数据创建子对象。
class PizzaOrderSerializer(serializer.ModelSerializer):
...
def create(self, validated_data):
items = validated_data.pop('items')
order = PizzaOrder.objects.create(**validated_data)
for item_data in items:
PizzaOrderItem.objects.create(pizza_order=order, **item_data)
return order
如果使用此方法,则可以使用POST数据创建订单:
{
"items": [
{ "pizza" : 1 },
{ "pizza" : 1 },
{ "pizza" : 2 },
{ "pizza" : 2 },
]
"status": 1
}