Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/backbone.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Django关系链接两个模型_Django - Fatal编程技术网

Django关系链接两个模型

Django关系链接两个模型,django,Django,我正在学习django,我正在做一个项目,制作一个比萨饼订购门户 我决定分别为浇头和比萨饼制作模型,以便以后可以添加更多的浇头,并为比萨饼选择其中的一种,但我似乎无法找出应该用于链接这两种浇头的关系模式 我偶然发现了外键方法,但这不是我想要的 以下是模型的代码部分: class Topping(models.Model): name = models.CharField(max_length = 30) def __str__(self): return self.name clas

我正在学习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()

请建议一种方法将这两者联系起来。

如果我正确理解你的意思,每个比萨饼都有很多配料,所以你必须使用多对多。这样,您可以添加任意数量的浇头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 = 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)
考虑到比萨饼有两种配料,您应该在配料中添加两个外键:

因此,我们在这里建立了一个比萨饼和一个配料连接两次的模型

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

我们可以使用a来实现这一点,如果我们希望能够添加两次或更多相同的浇头,我们可以使用直通表,如:

# 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()

在这里,您确实应该使用两个外键:一个用于第一个顶部,另一个用于第二个顶部。为什么你认为这不适用。外键将这两个链接在一起,但其他比萨也应该有它们的配料@WillemVanOnsemwell这正是外键所做的:每个比萨,你可以链接到两个配料。外键在面向对象的世界中或多或少就是一个引用。好的,我试着这样做。谢谢@WillemVanOnsemAnd,如果我想让它成为2,就像一个比萨饼必须有两个配料,那么这种关系会保持下去吗?或者我需要额外的功能来执行这条规则是的。您只需添加两个,您还可以确保浇头的数量至少等于2。但是,如果您可以订购两次相同的浇头,这里可能会出现问题。一些餐厅会这样做,两个相同的浇头意味着大部分浇头。但是,这可以通过一个直通表来解决。@AmineMessaoudi:完全正确。@AmineMessaoudi:不,我的意思是,在这里您只能添加topping1一次,如果您调用两次,第二次将无效。但是在一些餐馆,你想再加一次。谢谢你的帮助,有没有办法把这两种配料都作为外键比萨的独特配料method@rohan_aggarwal:什么意义上的独特:一个比萨饼应该有两种不同的配料,或者每个配料最多只能用于,一个比萨饼?一个比萨饼应该有两个不同的toppings@rohan_aggarwal:您可以在Django级别强制执行此操作,而不是在数据库级别,或者通过修补clean方法(如第一个代码片段中所示),在没有额外包的情况下强制执行此操作。或者,我也可以在表单中强制执行此操作
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()
# 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()