在Django中使用非外键加入约束

时间:2011-06-23 18:34:14

标签: sql django

在我的数据库中,我有一对表(tableAtableB),这两个表都有外键引用ID中的同一列tableC。我能够使用的SQL是

SELECT *
FROM tableA
INNER JOIN tableB on tableA.ID=tableB.ID
WHERE tableB.year=2011

查询

SELECT *
FROM tableA
INNER JOIN tableB on tableA.ID=tableB.ID AND tableB.year=2011

做了同样的事情

在Django中,我尝试使用代码

执行此操作
subquery=tableB.objects.filter(year=2011).values_list(id, flat=True)
results=tableA.objects.filter(id__in=list(subquery))

documentation中所述。我知道这有点不同,因为它只返回tableA中的列,但我只会使用它们。 Django代码似乎很慢,我想部分是因为tableA的每一行的集合成员资格测试,这是非常大的。有没有办法在不使用原始SQL的情况下在Django中加快速度(如果需要,我显然可以使用它)?

3 个答案:

答案 0 :(得分:1)

看起来你的模特不是很“django”友好。你使用一对一的关系,你的表pk是外键吗? (如果没有,请在问题中发布您的架构)。 Django更喜欢你的表(模型)主键是唯一的自动增量整数而不是外键。

django明智地说这更好:

class TableC(models.Model):
     name = models.CharField(max_length=1000)

class TableA(models.Model): 
     tablec = models.OneToOneField(TableC)

class TableB(models.Model): 
     tablec = models.OneToOneField(TableC)
     year = models.IntegerField()

请注意,所有字段都有一个(隐式)id字段,该字段是表的主键。现在执行:

TableA.objects.filter(tablec__tableb__year__exact=2011)

您实际上可以使用外键作为主键:

class TableC(models.Model):
     name = models.CharField(max_length=1000)

class TableA(models.Model): 
     tablec = models.OneToOneField(TableC, primary_key=True, db_column='id')

class TableB(models.Model): 
     tablec = models.OneToOneField(TableC, primary_key=True, db_column='id')
     year = models.IntegerField()

执行相同的查询。但是,这可能会在以后引起更多问题(“不保修”)。

答案 1 :(得分:1)

它很慢,因为它创建的查询可能看起来像

SELECT * FROM TableA WHERE ID IN (SELECT ID FROM TableB WHERE year=2011)

就像@Udi说的那样,如果你能通过添加外键来“django”来模仿模型,你会更好。否则,请使用RawSQL。这就是它的用途。

答案 2 :(得分:1)

不要将subquery转换为列表。如果你刚刚这样做了:

results=tableA.objects.filter(id__in=subquery)

Django应该足够聪明,可以实际执行子查询,而不是两个单独的查询。