Django模型继承问题。怎么解决?

时间:2010-10-06 09:24:11

标签: python django inheritance django-models django-orm

我有一个包含以下型号的现有应用

class Contact(models.Model):
     lastname = models.CharField(max_length=200)
     firstname = models.CharField(max_length=200)
     ...

class Journalist(Contact):
     pass

我的数据库中有Contact,我希望它变为Journalist

在原始sql中,它看起来像insert into app_journalist values (25624);一样简单。在此示例中,25624是现有联系人的ID。它似乎工作正常,django应用程序似乎很高兴。

但是,我想用django ORM做同样的事情。我尝试了几个想法强制记者身份证(Journalist(id=25624)),但它创建了一个新的联系人,而不是链接到现有的联系人。

使用Django ORM可以做到这一点吗?怎么样?

提前感谢您的帮助

3 个答案:

答案 0 :(得分:3)

解决此问题的一种方法是(不更改模型结构)将contact_ptr实例的Journalist属性设置为适当的Contact实例。例如,

contact = Contact.objects.get(pk = 25624)
journalist = Journalist(contact_ptr = contact)
journalist.save()

如果您首先查看表app_journalist,这将变得更容易理解。它只有一列contact_ptr_id。因此,当您执行insert into app_journalist values (25624)时,您将在SQL级别设置contact_ptr_id = 25624。相应地,您应该将contact_ptr = <instance of Contact>设置为ORM级别。

<强>更新

还有其他方法可以解决问题,但需要更改现有模型。作为@ bugspy.net pointed out,您可以使用通用关系。或者,您可以声明另外的type字段,以指定联系人是记者,同事等。

更新2

另请查看允许您使用多态继承demo snippet(以及complete code)(SQLAlchemy已经这样做了)。

更新3

正如@luc自己指出的那样(见下面的评论)

journalist = Journalist(contact_ptr = contact)
单靠这一点是不够的。这会覆盖firstname的{​​{1}}和lastnamecontact。为避免这种情况,您必须将每个字段明确指定给""

答案 1 :(得分:2)

Django的Contenttypes框架非常方便。 您可以使用它来表示不同的联系人类型:

from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic

class Contact(models.Model):
     lastname = models.CharField(max_length=200)
     firstname = models.CharField(max_length=200)
     content_object = generic.GenericForeignKey('content_type', 'object_id')

答案 2 :(得分:0)

模型级别的继承通常不是一个好主意。大多数ORM都允许你这样做。大多数ORM甚至为能够做到这一点感到自豪。在模型层面,着名的“prefer composition over inheritance”比以往更加真实。

在你的情况下,不是说:“记者是一个人”,你可以改为说:“一个人有工作,在这种情况下是记者”。这将由一个由Job类组成的Person类表示。其中一项工作可能是“记者”。

组合方法可让您更改工作,甚至可以拥有多个工作。

当然,这并没有直接回答你的问题,但其他答案已经相当不错了!