【问题标题】:Django model inheritance problem. How to solve?Django 模型继承问题。怎么解决?
【发布时间】:2010-10-06 09:24:10
【问题描述】:

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

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 可以做到这一点吗?怎么样?

提前感谢您的帮助

【问题讨论】:

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


    【解决方案1】:

    解决此问题的一种方法是(不更改模型结构)将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 = <instance of Contact>

    更新

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

    更新 2

    还可以看看这个demo snippet(和complete code),它允许您使用多态继承(SQLAlchemy 已经这样做了)。

    更新 3

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

    journalist = Journalist(contact_ptr = contact)
    

    单独是不够的。这会将contactfirstnamelastname 覆盖为""。为避免这种情况,您必须将每个字段显式分配给Journalist

    【讨论】:

    • 这似乎还不够,因为联系人的姓和名被空值覆盖。看来我也必须逐个字段地复制。 for a in contact.__dict__: if a != '_state': 记者.__dict__[a] = contact.__dict__[a] 无论如何,感谢您的宝贵帮助
    【解决方案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')
    

    【讨论】:

      【解决方案3】:

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

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

      组合方法让您可以让一个人换工作,甚至可以同时拥有多个工作。

      当然,这并不能直接回答你的问题,但是其他的答案已经很不错了!

      【讨论】:

      • 我同意你的观点,但它是一个现有的应用程序,改变模型并不容易
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-15
      相关资源
      最近更新 更多