2011-07-28 9 views
7

DjangoのORMを使用して簡単なtriplestoreを実装しようとしています。任意の複雑なトリプルパターン(たとえば、SparQLの場合と同じように)を検索することができるようにしたいと思います。DjangoのORM Extra()を使用して重複テーブルを含める

これを行うには、.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では、私は単純にやると思います。残念ながら

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') 

:私はそれはのラインに沿ったものだと思うが、

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とどのように見えるかを完全にはよく分かりません、これはエラーで失敗しない "DatabaseError:そのようなコラム: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') 

は、どこにも挿入されたtriple_tripleへの2番目の参照がないので、.extra()の呼び出しでテーブルのparamが無視されていることを示すようです。

どうしてですか? DjangoのORMを使用して同じテーブル内のレコード間の複雑な関係を参照する適切な方法は何ですか?

EDIT:これは、モデルマネージャ内で使用できるように、.extra()を使用してカスタムSQLを含めるためにこのが見つかりました。

答えて

10

私はこれが動作しているよう

何が欠けていること(余分なメソッドの)選択のパラメータであると思う:

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") 
+0

ありがとうございました。奇妙なのは、2番目のテーブルがWHERE句でフィルタリングされるときにクエリが中断されるため、SELECTで参照されなかったために追加のテーブルが削除されるということです。考えられるバグ? – Cerin

+0

@ Cerin:これはバグだとは思わないが、これは、where paramを使用してより多くの条件を設定し、返されたクエリーセットに列を追加することを選択するという汚い解釈です。 –

+0

@ Tommaso:私の主張は、各テーブルから少なくとも1つの列を選択しない限り、複数のテーブルを使用できないようです。これは理にかなっていません。なぜなら、私はいつもJOINしたい各テーブルの列をSELECTしたいと思うわけではないからです。だから私はこれがバグか、あまり設計されていない機能だと思うのです。 – Cerin

0

私はDjangoは(バック追加エスケープ同じ問題を持っていました-ticks)をテーブル名に追加します。つまり、エイリアスを手動で追加することはできません。 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

をしかし、元の表が一部であるため、これはおそらく、私のクエリのためのケースのように表示されません。簡単なFROM x、y、z句ではなく、LEFT OUTER JOINを使用します。

関連する問題