Django - ManyToMany 我可以多次 select 同一个外国模型

Django - ManyToMany where I could select the same foreign model multiple times

很抱歉,如果有人回答了这个问题,我不确定如何表达,所以找不到现有的解决方案。

假设我有一个基本的多对多关系,如下所示:

class Topping(models.Model):
    name = models.Charfield()

class Pizza(models.Model):
    toppings = models.ManyToMany(Topping)

这很简单也很棒,但是在我正在进行的项目中,我希望能够 select 多次使用相同的 Topping。例如,["pepperoni", "mushroom", "onion"] 将是一个非常好的结果,但我需要允许类似 ["pepperoni", "pepperoni", "pepperoni"]

我试过使用中间值 class,其中 Pizza 有一个 ManyToMany 到 Topping,它只是 ToppingType 的外键,即 Charfield -

class ToppingType(models.Model):
    name = models.Charfield()

class Topping(models.Model):
    type = models.ForeignKey(ToppingType)

class Pizza(models.Model):
    toppings = models.ManyToMany(Topping)

这行得通,但是这意味着如果有一天我用五个“意大利辣香肠”select离子创造了一些东西,那么我的数据库中就会永久拥有五个意大利辣香肠的副本作为浇头。

正如我在顶部提到的,我确信有一个相当干净的解决方案,但我在弄清楚如何用我的搜索措辞时遇到了麻烦。

你不需要 ManyToManyFieldTopping,你可以让 Topping 充当 junction table [wiki] and thus specify this as through=… model [Django-doc]:

class ToppingType(models.Model):
    name = models.Charfield(max_length=255, unique=True)

class Pizza(models.Model):
    toppings = models.ManyToMany(
        ToppingType,
        <b>through='Topping'</b>
    )

class Topping(models.Model):
    type = models.ForeignKey(ToppingType, on_delete=models.CASCADE)
    pizza = models.ForeignKey(Pizza, on_delete=models.CASCADE)

因此,您在此处为每个 pizza 每个浇头创建一个 Topping 对象。但是您不要复制 ToppingTypes。事实上,如果你没有指定 through=…,那么 Django 会创建一个(隐藏的)模型作为连接模型。

因此,您可以创建例如 ToppingTypes 意大利辣香肠和洋葱:

pepperoni = ToppingType.objects.create(name='pepperoni')
onion = ToppingType.objects.create(name='onion')

然后对于披萨添加 pepperonionionpepperoni:

my_pizza = Pizza.objects.create()
Topping.objects.create(<b>pizza=my_pizza, type=pepperoni</b>)
Topping.objects.create(<b>pizza=my_pizza, type=onion</b>)
Topping.objects.create(<b>pizza=my_pizza, type=pepperoni</b>)