使用 OneToOne 字段保存 django 模型时出错 - 指定两次列



这个问题以前有人问过,但那里的答案并不能解决我的问题。

我正在使用旧数据库,无法更改任何内容

这是我的 django 模型,除了相关字段之外的所有字段都被剥离了,显然类元在我的实际代码中具有 Managed=False:

class AppCosts(models.Model):
    id = models.CharField(primary_key=True)
    cost = models.DecimalField()
class AppDefs(models.Model):
    id = models.CharField(primary_key=True)
    data = models.TextField()
    appcost = models.OneToOneField(AppCosts, db_column='id')
class JobHistory(models.Model):
    job_name = models.CharField(primary_key=True)
    job_application = models.CharField()
    appcost = models.OneToOneField(AppCosts, to_field='id', db_column='job_application')
    app = models.OneToOneField(AppDefs, to_field='id', db_column='job_application')

一对一字段适用于查询,我使用 select_related() 得到正确的结果

但是当我为 JobHistory 表创建新记录时,当我调用 save() 时,我得到:

DatabaseError: (1110, "Column 'job_application' specified twice")

我正在使用django 1.4,但我不太明白这个OneToOneField是如何工作的。我找不到任何主键命名不同并且具有这种特定语义的示例

我需要 django 模型来让我做这个 SQL:

 select job_history.job_name, job_history.job_application, app_costs.cost from job_history, app_costs where job_history.job_application = app_costs.id;

您已将 appcost 和 app 定义为具有相同的基础数据库列 job_application这也是另一个现有字段的名称:因此三个字段共享同一列。这完全没有意义。

OneToOneFields 只是两端限制为单个值的外键。如果您有从 JobHistory 到 AppCost 和 AppDef 的外键,那么可能您的数据库中有包含这些外键的实际列。这些是您应该用于这些字段db_field的值,而不是"job_application"。

编辑 我很高兴你说你没有设计这个模式,因为它非常可怕:例如,你不会有任何外键约束,这使得引用完整性变得不可能。但没关系,我们实际上可以或多或少地实现您想要的。

您有各种问题,但主要的是您根本不需要单独的"job_application"字段。也就是说,正如我之前所说,外键,就这样吧。另请注意,它应该是实际的外键字段,而不是一对一的字段,因为一个应用程序有许多历史记录。

在 Django 中我们无法轻松实现的一个约束是让相同的字段充当两个表的 FK。但这并不重要,因为我们可以通过AppDefs获得AppCost。

所以模型可能看起来像这样:

class AppCosts(models.Model):
    app = models.OneToOneField('AppDefs', primary_key=True, db_field='id')
    cost = models.DecimalField()
class AppDefs(models.Model):
    id = models.CharField(primary_key=True)
    data = models.TextField()
class JobHistory(models.Model):
    job_name = models.CharField(primary_key=True)
    app = models.ForeignKey(AppDefs, db_column='job_application')

请注意,我已经将成本和 Defs 之间的一对一移动到 AppCost 上,因为在 Defs 中使用规范 ID 似乎是有意义的。

现在,给定一个 JobHistory 实例,您可以执行history.app来获取应用实例,history.app.cost获取应用成本,并使用history.app_id从job_application列获取基础应用 ID。

如果你想更准确地重现该 SQL 输出,现在可以像这样的事情工作:

JobHistory.objects.values_list('job_name', 'app_id', 'app__appcosts__cost')

最新更新