(这是一个老问题,但仍然是一个让人绊倒的领域,并且仍然与任何使用 Django 和预先存在的规范化模式的人高度相关。)
在您的 SELECT 语句中,您需要添加一个数字“id”,因为 Django 需要一个,即使在非托管模型上也是如此。如果某处的行上没有保证唯一的整数值,您可以使用 row_number() 窗口函数来完成此操作(对于视图,这通常是这种情况)。
在这种情况下,我使用了带有窗口函数的 ORDER BY 子句,但是您可以做任何有效的事情,并且当您使用它时,您还可以使用对您有用的子句。只要确保你不要尝试使用 Django ORM 点引用来引用关系,因为它们默认会查找“id”列,而你的是假的。
此外,如果您要在对象中使用它,我会考虑将输出列重命名为更有意义的名称。有了这些更改,查询看起来更像(当然,用您自己的术语替换“AS”子句):
CREATE VIEW qry_desc_char as
SELECT
row_number() OVER (ORDER BY tbl_char.cid) AS id,
tbl_desc.iid_id AS iid_id,
tbl_desc.cid_id AS cid_id,
tbl_desc.cs AS a_better_name,
tbl_char.cid AS something_descriptive,
tbl_char.charname AS name
FROM tbl_desc,tbl_char
WHERE tbl_desc.cid_id = tbl_char.cid;
完成后,在 Django 中,您的模型可能如下所示:
class QryDescChar(models.Model):
iid_id = models.ForeignKey('WhateverIidIs', related_name='+',
db_column='iid_id', on_delete=models.DO_NOTHING)
cid_id = models.ForeignKey('WhateverCidIs', related_name='+',
db_column='cid_id', on_delete=models.DO_NOTHING)
a_better_name = models.CharField(max_length=10)
something_descriptive = models.IntegerField()
name = models.CharField(max_length=50)
class Meta:
managed = False
db_table = 'qry_desc_char'
您不需要 id 列名称末尾的“_id”部分,因为您可以像我上面所做的那样使用“db_column”参数在 Django 模型上使用更具描述性的内容声明列名称(但这里我只有它防止 Django 添加另一个"_id" 到 cid_id 和 iid_id 的末尾——这为您的代码添加了零语义值)。另外,请注意“on_delete”参数。当涉及到级联删除时,Django 会做自己的事情,而在一个有趣的数据模型上你不希望这样做——当涉及到视图时,你只会得到一个错误和一个中止的事务。在 Django 1.5 之前,您必须对其进行修补以使 DO_NOTHING 实际上意味着“什么都不做”——否则它仍会尝试(不必要地)在执行删除周期之前查询并收集所有相关对象,并且查询将失败,停止整个操作。
顺便说一句,就在前几天,我写了一篇关于如何做到这一点的深入解释 。