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

时间:2015-01-02 22:25:48

标签: python django

之前已经问过这个问题,但那里的答案并没有解决我的问题。

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

以下是我的django模型,除了相关字段之外的所有模型都被剥离了,显然类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;

1 个答案:

答案 0 :(得分:1)

您已将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获取基础应用ID job_application列。

如果您想更准确地再现该SQL输出,现在可以使用以下内容:

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