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

Error saving django model with OneToOne field - Column specified twice

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

我使用的是遗留数据库,无法更改任何内容

这是我的 Django 模型,除了相关字段之外的所有字段都被删除,显然 class meta 在我的实际代码中有 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')

OneToOne 字段非常适合查询,我使用 select_related()

得到了正确的结果

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

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

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

我需要可以执行此 SQL 的 django 模型:

 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 获取 AppCosts。

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

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')

请注意,我已将 Costs 和 Defs 之间的一对一转移到 AppCosts 上,因为在 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')