之前已经问过这个问题,但那里的答案并没有解决我的问题。
我正在使用遗留数据库,无法更改任何内容
以下是我的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;
答案 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')