多表继承模型和相同两个模型之间的简单一对一关系有啥区别?

Posted

技术标签:

【中文标题】多表继承模型和相同两个模型之间的简单一对一关系有啥区别?【英文标题】:What is the difference between a Multi-table inherited model and a simple One-to-one relationship between the same two models?多表继承模型和相同两个模型之间的简单一对一关系有什么区别? 【发布时间】:2013-08-19 23:58:08 【问题描述】:

这些实现之间有什么区别? Django 有什么不同(除了继承 Meta orderingget_latest_by 属性)?

1.

# models.py
from django.db import models

class Place(models.Model):
    name = models.CharField(max_length=50)

class Restaurant(models.Model):
    place = models.OneToOneField(Place)
    serves_pizza = models.BooleanField()

2.

class Place(models.Model):
    name = models.CharField(max_length=50)

class Restaurant(Place):
    serves_pizza = models.BooleanField()

3.

class Place(models.Model):
    name = models.CharField(max_length=50)

class Restaurant(Place):
    place = models.OneToOneField(Place, parent_link=True)
    serves_pizza = models.BooleanField()

【问题讨论】:

我想用额外的字段扩展内置站点框架站点模型并尝试确定哪种方法最好。 【参考方案1】:

1.你并没有真正得到任何python继承,也就是说你不能在你的类Restaurant中继承/覆盖模型类Place的方法或属性:

例如:

class Place(models.Model):
    name = models.CharField(max_length=50)

    def get_x(self):
        return 'x'

class Restaurant(models.Model):
    place = models.OneToOneField(Place)
    serves_pizza = models.BooleanField()

a_restaurant = Restaurant()
a_restaurant.get_x() # -> wouldn't work

这意味着要获得您不能做a_restaurant.name的餐厅的name,您需要点击链接:a_restaurant.place.name

另请注意,在使用相关的Restaurant 查询Place 对象时。

a_restaurant.save()
Place.objects.get(pk=a_restaurant.pk)  # won't work

你必须写:

a_restaurant.save()
Place.objects.get(restaurant__pk=a_restaurant.pk)

2 和 3。几乎一样。你确实得到了真正的 python 继承。

a_restaurant = Restaurant()
a_restaurant.get_x() # would actually work and print 'x'

您的模型类Restaurant 继承自Place 的所有内容:模型字段、普通实例/类属性、管理器、方法......您还可以覆盖几乎所有这些: 您不能覆盖字段属性,这是不受支持的。

所以现在您可以直接从父模型中获取字段的值:a_restaurant.name,因为它们是继承的。

由于有了这些实现,Restaurant 也是Place,您可以使用Restaurant 数据查询Place 对象:

a_restaurant.save()
the_place = Place.objects.get(pk=a_restaurant.pk)  
# ^ this works now and returns the equivalent `Place` instance.
the_same_restaurant = the_place.restaurant

2 和 3 之间的区别如果您给该字段指定不同的名称,则更容易看出:

class Place(models.Model):
    name = models.CharField(max_length=50)

class Restaurant(Place):
    where = models.OneToOneField(Place, parent_link=True)
    serves_pizza = models.BooleanField()

工作原理完全相同,但要获得Restaurant 的父位置,属性名称为where

the_place = a_restaurant.where

使用 2 会是:

the_place = a_restaurant.place_ptr

这意味着place = models.OneToOneField(Place, parent_link=True) 只会更改指向父模型实例的链接名称。默认名称为'lowercase_model_name_ptr'


最后一个例子:

使用 1

place1 = Place.objects.create(name='place_1')
place2 = Place.objects.create(name='place_2')
restaurant1 = Restaurant.objects.create(place=place1, serves_pizza=True)

print Place.objects.all() # prints [place1, place2]
print Restaurant.objects.all() # prints [restaurant1]

2-3

place1 = Place.objects.create(name='place_1')
place2 = Place.objects.create(name='place_2')
restaurant1 = Restaurant.objects.create(name='place_3', serves_pizza=True)

print Place.objects.all() # prints [place1, place2, place3]
print Restaurant.objects.all() # prints [restaurant1]

希望这些有所帮助。它长得有点太长了:/

【讨论】:

我个人意见:2º 选项似乎是本示例的最佳实现,因为Restaurant 确实是Place 很好的解释,没想到这么长 :) 谢谢! 注意:在 Django 1.5 中,子模型中 OneToOneField 的默认名称是 objectname.parentobject_ptr(不是 objectname.parentobject)。因此,您可以在#2 中使用a_restaurant.place_ptr 查询地点。但反过来(从地方查询)它是:a_place.restaurant @Adrian 你必须写:a_restaurant.save() Place.objects.get(restaurant__pk=a_restaurant.pk) 如果餐厅派生自/包含地方,我不明白我们怎么写 restaurant__pk ,而不是反过来。谢谢 @dowjones123 Django 可以向后跟踪(和查询)关系。看看docs.djangoproject.com/en/dev/topics/db/queries/…,docs.djangoproject.com/en/dev/topics/db/queries/…,特别是docs.djangoproject.com/en/dev/topics/db/queries/…【参考方案2】:

1 - 要创建餐厅,您需要创建地点,创建餐厅后,链接它们后, 2 - 然后创建餐厅,自动创建和链接新地点, 3 - 您将父链接重命名为地点。

使用带有内容类型的模型继承,您可以列出所有在 Place.objects.all() 上迭代的咖啡馆、餐馆、酒吧等

【讨论】:

以上是关于多表继承模型和相同两个模型之间的简单一对一关系有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

web框架开发-Django模型层-多表操作

16-CoreData之多表关联(存储自定义数据模型)

Django框架(模型层:多表查询)

django模型层2 多表操作

Django-5.2 模型层 多表操作

ORM多表操作(object与queryset)