我有一个包含以下型号的现有应用
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可以做到这一点吗?怎么样?
提前感谢您的帮助
答案 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}}和lastname
到contact
。为避免这种情况,您必须将每个字段明确指定给""
。
答案 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类表示。其中一项工作可能是“记者”。
组合方法可让您更改工作,甚至可以拥有多个工作。
当然,这并没有直接回答你的问题,但其他答案已经相当不错了!