【问题标题】:Django ORM: child's fields & values not inherited. Objects duplicated. (Using Django admin interface)Django ORM:孩子的字段和值未继承。对象重复。 (使用 Django 管理界面)
【发布时间】:2020-08-18 11:53:56
【问题描述】:

我正在尝试从一个普通(具体)父级继承的各种菜肴(比萨饼、潜艇等) class Dish。 (从逻辑上讲,除了遇到困难之外,我没有理由让它变得具体 实现它)。

每个比萨饼(或其他具体菜肴)都对应一个菜肴 ID(在此处实现为 FK),并且每个 菜 (ID) 正好是一个披萨。

我是新手,但根据我的理解,共享字段(名称、类型价格、大小和菜肴 ID(PK 对于Dish = FK dish_id 对于Pizza)) 在Dish 以及它们的值 由子代继承,例如Pizza。理论就讲这么多。

现在我按照下面的方法实现了这些类。然后我使用 Django Admin 界面创建对象,但是 出乎意料的是,当我创建一个“Pizza”类型的Dish 对象时,Pizza 对象自动是 创建的。现在,当我进入那个Pizza 对象时,名称、类型、价格和大小字段都是空白的。 当我选择Pizzadish 属性作为Dish-object 时,它们不应该被设置吗 我刚刚创建?

当我开始创建 Pizza 时,选择相应的父级(或在 Django 管理界面),我需要填充所有公共字段两次(一次在Dish,然后再次在Pizza)。

无论我采用哪种方式,我都会得到重复的条目:我创建的 Pizza 对象的 1 个披萨 和 1 个我为该披萨创建的 Dish 类型的披萨。 (反之亦然,1 道菜用于制作的菜肴和 1 道菜用于我制作的披萨)。

我的错误是什么,是设计缺陷还是我创建数据库条目的方式?

class Dish(models.Model):
  PIZZA = 'PIZZA'
  SUB = 'SUB'
  PASTASALAD = 'PASTASALAD'
  PLATTER = 'PLATTER'
  TYPE_CHOICES = ( (PIZZA, 'Pizza'), (SUB, 'Sub'), (PASTASALAD, 'PastaSalad'), (PLATTER, 'Platter') )
  name = models.CharField(max_length=64, blank=True) # blank makes name optional
  type = models.CharField(max_length=64, choices=TYPE_CHOICES, blank=True)
  size = models.CharField(max_length=1, choices=SIZE_CHOICES, default=SMALL, blank=True)
  price = models.DecimalField(max_digits=6, decimal_places=2, default=None)

class Pizza(Dish):
  dish = models.ForeignKey(Dish, on_delete=models.CASCADE, related_name="dish_id_pizza")
  REGULAR = 'REGULAR'
  SICILIAN = 'SICILIAN'
  STYLE_CHOICES = ( (REGULAR, 'Regular'), (SICILIAN, 'Sicilian'),)
  style = models.CharField(max_length=7, choices=STYLE_CHOICES, default=REGULAR)
  topping_count = models.IntegerField(default=0, validators=[MaxValueValidator(5), MinValueValidator(0)])

【问题讨论】:

    标签: django django-models orm django-orm


    【解决方案1】:

    利用 OneToOne 关系,因为你想要一个。

    class Pizza(models.Model):
        dish = models.OneToOneField(Dish, on_delete=models.CASCADE, related_name="dish_id_pizza")
    

    这应该可以解决重复问题并预先填充自身和空白字段。

    注意:您还应该编写 str dunder 方法来轻松跟踪每个模型字段。像这样。

    def __str__(self):
        return f"{self.name}"
    

    【讨论】:

    • 谢谢你——我想这几乎让我明白了。我注意到虽然在您的示例中 Pizza 没有从 Dish 继承 - 这是故意的吗? (我确实写了 str - 只是把它放在这里了,但感谢您的提示!!:))
    • 我刚刚将其更改为dish = models.OneToOneField(Dish, on_delete=models.CASCADE, related_name="dish_id_pizza", parent_link=True),但现在我在 Django 管理界面中根本看不到任何链接。 dish 字段已从 Pizza 完全消失,所以我无法告诉 Django 链接到哪个父级,因此再次提示填充大小、价格等。
    • 我想要一个Dish,其中属性(字段)价格、名称、类型和大小与对应的子Pizza 对象继承(共享,即相同)。因此,如果我的 ID #17 的菜对象是 type=Pizza, price=20, size=L, name=Cheese - 从逻辑上讲,它的子 Pizza 对象应该具有所有这些完全相同的特征,但它们是空白的,我不仅可以,但必须覆盖它们。 DishPizza 对象不应该通过 OneToOne ID 17 链接吗?
    • @Anna 我在处理您的代码时发现了一些东西。尝试填充子表中的字段,您会注意到父表 Dish 已自动填充并链接到子表 Pizza。您还可以将父类抽象化。
    • 这是我将 Dish 抽象化的问题。一旦我包含class Meta: abstract = True,我就会遇到一堆错误。即:orders.Pizza.dish: (fields.E300) Field defines a relation with model 'orders.Dish', which is either not installed, or is abstract. orders.Pizza.dish: (fields.E307) The field orders.Pizza.dish was declared with a lazy reference to 'orders.dish', but app 'orders' doesn't provide model 'dish'. 根据其他帖子的建议,我尝试将应用名称包含在:dish = models.OneToOneField('orders.Dish', .. 中,但这也不起作用:(
    猜你喜欢
    • 2011-05-08
    • 1970-01-01
    • 2023-03-07
    • 2010-09-23
    • 1970-01-01
    • 2013-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多