【问题标题】:Django ManyToManyField with many same IDs具有许多相同 ID 的 Django ManyToManyField
【发布时间】:2019-10-24 08:54:22
【问题描述】:

我正在尝试在 Django 中制作一个简单的披萨订购应用。我有 3 个模型(浇头、比萨饼、订单)。在 Orders 模型中有 ManyToManyField 到 Pizza。如果“用户”为每个披萨(例如玛格丽塔和意大利辣香肠)订购一个,则工作正常,但如果在 POST 请求中订购 2 个玛格丽塔,我的结果中只有一个玛格丽塔 ID。我如何在一个订单中通过 n-pizzas?

我的模型如下所示:

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
}

Order 的序列化器和视图

class OrdersSerializer(serializers.ModelSerializer):

    class Meta:
        model = PizzaOrder
        fields = ['id', 'items', 'status', 'created']


class PizzaOrdersList(ModelViewSet):
    queryset = PizzaOrder.objects.all()
    serializer_class = OrdersSerializer

【问题讨论】:

  • 因为项目引用了比萨模型。所以 1 Order A 对 Pizza1 的引用 1000 次,那么它仍然是 1 Oder A 对 1 Pizza1 的引用。我认为您需要创建一个 PizzaOrderItem,其中包含对 Pizza 的引用以及这种比萨的数量
  • 你能展示 PizzaOrderItem 模型的例子以及如何从 Oder 发布请求中计算项目吗?
  • 下面的答案已经回答了你的问题..这是一个很好的答案

标签: sql django django-rest-framework foreign-keys


【解决方案1】:

直通模型非常适合这一点。 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 = PizzaOrderItem
        # 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 视图,并将创建函数覆盖到 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
}

【讨论】:

  • 很好的答案!作为参考,这里是关于这个主题的相关文档:docs.djangoproject.com/en/2.2/topics/db/models/…
  • 非常感谢!我的订单序列化程序类 OrdersSerializer(serializers.ModelSerializer): class Meta: model = PizzaOrder fields = ['id', 'items', 'status', 'created']
  • 你能帮忙处理序列化器和视图吗?
  • 是的,我离开了一段时间。我已经更新了答案
  • 它实际上不起作用。 { "pizza_order": [ "无效的 pk \"1\" - 对象不存在。" ]} 那么 AuthorsOrder 是什么?
猜你喜欢
  • 1970-01-01
  • 2023-03-29
  • 2016-11-30
  • 2015-06-24
  • 2014-11-21
  • 2017-06-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多