Django模型继承问题。怎么解决?
我有一个具有以下模型的现有应用程序
class Contact(models.Model):
lastname = models.CharField(max_length=200)
firstname = models.CharField(max_length=200)
...
class Journalist(Contact):
pass
,我的数据库中有一个联系人
,我希望它成为记者
。
在原始 SQL 中,它看起来就像 insert into app_journalist value (25624);
一样简单。在此示例中,25624 是现有联系人的 ID。它似乎工作正常,django 应用程序看起来很高兴。
然而,我想用 django ORM 做同样的事情。我尝试过几种想法,例如强制记者 ID (Journalist(id=25624)
),但它会创建一个新联系人,而不是链接到现有联系人。
可以用 Django ORM 做到这一点吗?如何?
预先感谢您的帮助
I have an existing app with the following model
class Contact(models.Model):
lastname = models.CharField(max_length=200)
firstname = models.CharField(max_length=200)
...
class Journalist(Contact):
pass
I have a Contact
in my database and I would like that it becomes a Journalist
.
In raw sql, it seems as simple as insert into app_journalist values (25624);
. In this example 25624 is the id of the existing contact. It seems to work ok and the django app seems happy.
However, I would like to make the same thing with the django ORM. I have tried several thinks like forcing the journalist id (Journalist(id=25624)
) but it creates a new contact rather than linking to the existing one.
Is it possible do to that with the Django ORM? How?
Thanks in advance for your help
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
解决此问题的一种方法是将
Journalist
实例的contact_ptr
属性设置为适当的Contact
实例(无需更改模型结构)。例如,如果您首先查看表
app_journalist
,这会更容易理解。它只有一列,contact_ptr_id
。因此,当您执行insert into app_journalist value (25624)
时,您将在 SQL 级别设置contact_ptr_id = 25624
。相应地,您应该在 ORM 级别设置contact_ptr =
。更新
还有其他方法可以解决该问题,但它们需要更改您现有的模型。正如@bugspy.net 指出你可以使用一种通用关系。或者,您可以声明一个附加的
type
字段来指定联系人是否是记者、同事等。更新 2
另请查看此 演示片段 (以及 完整代码),让您可以使用多态继承(SQLAlchemy 已经做到了这一点)。
更新 3
正如 @luc 本人指出的那样(请参阅下面的评论),
仅靠这一点是不够的。这会将
联系人
的名字
和姓氏
覆盖为""
。为了避免这种情况,您必须将每个字段显式分配给Journalist
。One way to solve this is (without changing your model structure) to set the
contact_ptr
attribute of theJournalist
instance to the appropriateContact
instance. For e.g.This becomes easier to understand if you first look at the table
app_journalist
. It has but one column,contact_ptr_id
. So when you executeinsert into app_journalist values (25624)
you are settingcontact_ptr_id = 25624
at the SQL level. Correspondingly you should set thecontact_ptr = <instance of Contact>
at the ORM level.Update
There are other ways to solve the problem but they would require changes to your existing models. As @bugspy.net pointed out you can use a generic relationship. Alternately you can declare an additional
type
field to specify whether the contact is a journalist, a colleague etc.Update 2
Also take a look at this demo snippet (and the complete code) that lets you use polymorphic inheritance (SQLAlchemy already does this).
Update 3
As @luc himself pointed out (see comment below)
alone will not suffice. This will overwrite the
firstname
andlastname
of thecontact
to""
. To avoid this you have to explicitly assign each field toJournalist
.Django 的 Contenttypes 框架非常方便。
您可以使用它来表示不同的联系人类型:
Django's Contenttypes framework is really handy.
You could use it to represent different contact types:
模型级别的继承通常不是一个好主意。大多数 ORM 都允许您这样做。大多数 ORM 甚至为能够做到这一点而感到自豪。在模型级别,著名的“更喜欢组合而不是继承”比以往任何时候都更加真实。
在您的情况下,您可以说:“一个记者就是一个人”,而不是说:“一个人有一份工作,在本例中是记者”。这将由由 Job 类组成的 Person 类来表示。其中一项工作可能是“记者”。
组合方法可以让一个人换工作,甚至身兼数职。
当然,这并不能直接回答你的问题,但其他答案已经相当不错了!
Inheritance at the model level is usually not such a good idea. Most ORM let you do it. Most ORM are even proud to be able to do it. At the model level, the famous "prefer composition over inheritance" is more true than ever.
In your case, instead of saying : "A journalist IS A person", you could instead say : "A person has a job, which in this case is journalist". This would be represented by a Person class composed with a Job class. One of the job could be "journalist".
The composition approach lets you have a person change job, or even have multiple jobs.
Of course, this doesnt directly answer your question, but the other answers are already pretty good !