Django Relationship链接两个模型

时间:2018-11-26 19:59:59

标签: django

我正在学习django,并且我正在做一个制作比萨订购门户的项目。

我决定分别制作浇头和比萨饼的模型,以便以后可以添加更多的浇头,并为其中的比萨饼选择模型,但是我似乎无法弄清楚应该用于链接这两者的关系模式

我偶然发现了外键方法,但这不是我想要的 这是模型代码的一部分:

class Topping(models.Model):
name = models.CharField(max_length = 30)

def __str__(self):
    return self.name

class Pizza(models.Model):
    name = models.CharField(max_length=40)
    first_toppping = models.Topping()
    second_topping = models.Topping()
    # in inches
    size = models.IntegerField(max_length=3)
    price = models.FloatField()

请提出一种链接这两者的方法。

2 个答案:

答案 0 :(得分:2)

如果我很了解您,每个比萨饼都有很多浇头,所以您必须使用很多。这样,您可以添加任意数量的浇头(0-*)

class Topping(models.Model):
    name = models.CharField(max_length = 30, unique = True)

    def __str__(self):
        return self.name

class Pizza(models.Model):
    name = models.CharField(max_length=40)
    toppings = models.ManyToManyField(Topping)
    # in inches
    size = models.IntegerField(max_length=3)
    price = models.FloatField()

如以下示例所示,我创建了一个披萨对象,并添加了所需的浇头:

pizza = Pizza(name="CheesePizza",size=5,price=25.22)
pizza.save()

topping1 = Topping(name="chocolate")
topping1.save()
topping2 = Topping(name="whataver")
topping2.save()
topping3 = Topping(name="component")
topping3.save()

pizza.toppings.add(topping1,topping2,topping3)

答案 1 :(得分:1)

鉴于Pizza有两个Topping,则应在ForeignKey上添加两个Topping

from django.utils.translation import gettext_lazy as _

class Topping(models.Model):
    # ...
    pass

class Pizza(models.Model):
    name = models.CharField(max_length=40)
    first_toppping = models.ForeignKey(
        Topping,
        on_delete=models.DO_NOTHING,
        related_name='pizza_first'
    )
    second_topping = models.ForeignKey(
        Topping,
        on_delete=models.DO_NOTHING,
        related_name='pizza_second'
    )

    size = models.IntegerField(max_length=3)
    price = models.FloatField()

    def clean(self):
        # given we want the two toppings to be different
        if self.first_topping_id == self.second_topping_id:
            raise ValidationError(_('Toppings should be different.'))
        return super(Pizza, self).clean()

或者您可以使ForeignKey可以为空,这样,如果其中一个浇头是NULL,则这意味着我们不选择第一/第二浇头:

from django.utils.translation import gettext_lazy as _

class Topping(models.Model):
    # ...
    pass

class Pizza(models.Model):
    name = models.CharField(max_length=40)
    first_toppping = models.ForeignKey(
        Topping,
        on_delete=models.SET_NULL,
        null=True,
        related_name='pizza_first'
    )
    second_topping = models.ForeignKey(
        Topping,
        on_delete=models.SET_NULL,
        null=True,
        related_name='pizza_second'
    )

    size = models.IntegerField(max_length=3)
    price = models.FloatField()

    def clean(self):
        # given we want the two toppings to be different
        if self.first_topping_id is not None and self.second_topping_id is not None and self.first_topping_id == self.second_topping_id:
            raise ValidationError(_('Toppings should be different.'))
        return super(Pizza, self).clean()

因此,我们在此建模比萨饼两次链接到浇头。

根据应用程序,您可能希望允许用户选择任意数量的浇头,有时甚至可以多次选择相同浇头。

为此,我们可以使用ManyToManyField [Django-doc],并且如果我们希望能够将相同的顶部添加两次(或更多),则可以使用through表,例如:

# a pizza can have the same topping multiple times

class Topping(models.Model):
    # ...
    pass

class PizzaTopping(models.Model):
    pizza = models.ForeignKey('Pizza')
    topping = models.ForeignKey(Topping)

class Pizza(models.Model):
    name = models.CharField(max_length=40)
    toppping = models.ManyToManyField(
        Topping,
        through=PizzaTopping,
        related_name='pizzas'
    )

    size = models.IntegerField(max_length=3)
    price = models.FloatField()