我正在尝试使用Django的ORM实现一个简单的三元组。我希望能够搜索任意复杂的三重模式(例如,与SparQL一样)。
为此,我尝试使用.extra()方法。但是,即使文档提到它,理论上也可以通过自动为重复表引用创建别名来处理对同一个表的重复引用,我发现它在实践中不会这样做。
例如,假设我的“三重”应用程序中有以下模型:
class Triple(models.Model):
subject = models.CharField(max_length=100)
predicate = models.CharField(max_length=100)
object = models.CharField(max_length=100)
我的数据库中存储了以下三元组:
subject predicate object
bob has-a hat .
bob knows sue .
sue has-a house .
bob knows tom .
现在,说我想查询每个人的名字鲍勃知道谁有房子。在SQL中,我只是这样做:
SELECT t2.subject AS name
FROM triple_triple t1
INNER JOIN triple_triple t2 ON
t1.subject = 'bob'
AND t1.predicate = 'knows'
AND t1.object = t2.subject
AND t2.predicate = 'has-a'
AND t2.object = 'house'
我不完全确定使用Django的ORM会是什么样子,虽然我认为它会是这样的:
q = Triple.objects.filter(subject='bob', predicate='knows')
q = q.extra(tables=['triple_triple'], where=["triple_triple.object=t1.subject AND t1.predicate = 'has-a' AND t1.object = 'house'"])
q.values('t1.subject')
不幸的是,这失败并出现错误“DatabaseError:no such column:t1.subject”
运行打印q.query显示:
SELECT "triple_triple"."subject" FROM "triple_triple" WHERE ("triple_triple"."subject" = 'bob' AND "triple_triple"."predicate" = 'knows'
AND triple_triple.object = t1.subject AND t1.predicate = 'has-a' AND t1.object = 'house')
这似乎表明我对.extra()的调用中的表格被忽略了,因为没有第二次引用到任何地方插入的triple_triple。
为什么会这样?使用Django的ORM在同一个表中的记录之间引用复杂关系的适当方法是什么?
编辑:我发现这个useful snippet用于通过.extra()包含自定义SQL,以便它可以在模型管理器中使用。
答案 0 :(得分:13)
我认为你缺少的是select参数(对于额外的方法)
这似乎有效:
qs = Triple.objects.filter(subject="bob", predicate="knows").extra(
select={'known': "t1.subject"},
tables=['"triple_triple" AS "t1"'],
where=['''triple_triple.object=t1.subject
AND t1.predicate="has-a" AND t1.object="'''])
qs.values("known")
答案 1 :(得分:0)
我遇到了同样的问题,Django在我的表名中逃脱(添加反向标记),这意味着我无法手动添加别名;生成的FROM子句如下所示:
"mytable" AS T100
但与此同时,如果已经提到过表,Django不会自动为你创建别名;相反,它忽略了表,只是添加WHERE子句,就像它们引用原始表一样。
Django 1.8的文档表明.extra()将为您创建别名:
https://docs.djangoproject.com/en/1.8/ref/models/querysets/#django.db.models.query.QuerySet.extra
但是我的查询似乎不是这样,可能是因为原始表是LEFT OUTER JOIN的一部分而不是简单的FROM x,y,z子句。