Django模型继承问题. 如何解决?
我有一个现成的应用,里面有一个模型
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来实现同样的功能。我尝试了几种方法,比如强制指定记者的ID(Journalist(id=25624)
),但这样会创建一个新的联系人,而不是链接到已有的那个。
用Django的ORM能做到这一点吗?怎么做呢?
提前感谢你的帮助
3 个回答
在模型层面上使用继承通常不是个好主意。大多数ORM(对象关系映射)工具都允许你这样做,甚至为此感到自豪。但在模型层面上,著名的“更喜欢组合而不是继承”这句话比以往任何时候都更真实。
在你的例子中,不如说:“一个记者是一个人”,可以改成:“一个人有一个工作,而这个工作是记者”。这可以通过一个“人”类和一个“工作”类来表示。工作之一可以是“记者”。
使用组合的方法可以让你方便地改变一个人的工作,甚至让一个人有多个工作。
当然,这并没有直接回答你的问题,但其他的回答已经相当不错了!
Django的内容类型框架非常实用。你可以用它来表示不同的联系方式类型:
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')
解决这个问题的一种方法是(不改变你的模型结构)将Journalist
实例的contact_ptr
属性设置为相应的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
。相应地,你应该在ORM层面上设置contact_ptr = <Contact的实例>
。
更新
还有其他方法可以解决这个问题,但它们需要对你现有的模型进行修改。正如@bugspy.net 指出的,你可以使用通用关系。或者,你可以声明一个额外的type
字段,用来指定这个联系人是记者、同事等。
更新 2
还可以看看这个 演示代码(以及 完整代码),它让你使用多态继承(SQLAlchemy已经支持这个功能)。
更新 3
正如@luc自己指出的(见下面的评论)
journalist = Journalist(contact_ptr = contact)
单靠这个是不够的。这会把contact
的firstname
和lastname
覆盖成""
。为了避免这种情况,你必须明确地将每个字段分配给Journalist
。