在Django-Model继承中,是否允许重写父模型的属性?

2024-03-28 16:26:23 发布

您现在位置:Python中文网/ 问答频道 /正文

我想这样做:

class Place(models.Model):
   name = models.CharField(max_length=20)
   rating = models.DecimalField()

class LongNamedRestaurant(Place):  # Subclassing `Place`.
   name = models.CharField(max_length=255)  # Notice, I'm overriding `Place.name` to give it a longer length.
   food_type = models.CharField(max_length=25)

这是我想使用的版本(尽管我愿意接受任何建议): http://docs.djangoproject.com/en/dev/topics/db/models/#id7

Django支持这个吗?如果没有,是否有办法达到类似的效果?


Tags: tonamemodelmodelsplacelengthmaxclass
3条回答

除非是抽象的,否则这是不可能的,这就是为什么:LongNamedRestaurant也是一个Place,不仅作为一个类而且在数据库中。place表包含每个纯Place和每个LongNamedRestaurant的条目。LongNamedRestaurant只需创建一个带有food_type和对place表的引用的额外表。

如果你做了Place.objects.all(),你也得到了每个LongNamedRestaurant的地方,它将是Place(没有food_type)的一个实例。因此Place.nameLongNamedRestaurant.name共享同一数据库列,因此必须属于同一类型。

我认为这对普通模特来说是有意义的:每家餐馆都是一个地方,至少应该有那个地方所有的东西。也许这种一致性也是为什么1.10之前的抽象模型不可能实现的原因,尽管它不会带来数据库问题。正如@lampsave所说,这是在1.10中实现的。我个人建议注意:如果Sub.x重写Super.x,请确保Sub.x是Super.x的子类,否则不能使用Sub代替Super。

解决方法:您可以创建一个自定义用户模型(AUTH_USER_MODEL),如果只需要更改email字段,则该模型会涉及相当多的代码重复。或者你可以留下电子邮件,并确保它是所有形式的要求。如果其他应用程序使用它,这不能保证数据库的完整性,也不能以其他方式工作(如果您想使用户名成为不需要的)。

不,it is not

Field name “hiding” is not permitted

In normal Python class inheritance, it is permissible for a child class to override any attribute from the parent class. In Django, this is not permitted for attributes that are Field instances (at least, not at the moment). If a base class has a field called author, you cannot create another model field called author in any class that inherits from that base class.

更新的答案:正如人们在评论中指出的,最初的答案没有正确回答问题。实际上,只有LongNamedRestaurant模型是在数据库中创建的,Place不是。

解决方案是创建一个抽象模型来表示一个“地方”,例如AbstractPlace,并从中继承:

class AbstractPlace(models.Model):
    name = models.CharField(max_length=20)
    rating = models.DecimalField()

    class Meta:
        abstract = True

class Place(AbstractPlace):
    pass

class LongNamedRestaurant(AbstractPlace):
    name = models.CharField(max_length=255)
    food_type = models.CharField(max_length=25)

也请阅读@Markanswer,他给出了一个很好的解释,为什么不能更改从非抽象类继承的属性。

(注意,这是唯一可能的,因为Django 1.10:在Django 1.10之前,无法修改从抽象类继承的属性。)

Original answer

Since Django 1.10 it's possible! You just have to do what you asked for:

class Place(models.Model):
    name = models.CharField(max_length=20)
    rating = models.DecimalField()

    class Meta:
        abstract = True

class LongNamedRestaurant(Place):  # Subclassing `Place`.
    name = models.CharField(max_length=255)  # Notice, I'm overriding `Place.name` to give it a longer length.
    food_type = models.CharField(max_length=25)

相关问题 更多 >