6

ドキュメントによると:

filter(**kwargs) 指定されたルックアップ パラメーターに一致するオブジェクトを含む新しい QuerySet を返します。

ルックアップ パラメーター (**kwargs) は、以下のフィールド ルックアップで説明されている形式である必要があります。複数のパラメーターは、基になる SQL ステートメントで AND を介して結合されます。

元のセットにあったアイテムのサブセットを返すことを示唆しています。ただし、以下の例は期待どおりに動作しないため、何かが欠けているようです。

>>> kids = Kid.objects.all()
>>> tuple(k.name for k in kids)
(u'Bob',)
>>> toys = Toy.objects.all()
>>> tuple( (t.name, t.owner.name) for t in toys)
((u'car', u'Bob'), (u'bear', u'Bob'))
>>> subsel = Kid.objects.filter( owns__in = toys )
>>> tuple( k.name for k in subsel )
(u'Bob', u'Bob')
>>> str(subsel.query)
'SELECT "bug_kid"."id", "bug_kid"."name" FROM "bug_kid" INNER JOIN "bug_toy" ON ("bug_kid"."id" = "bug_toy"."owner_id") WHERE "bug_toy"."id" IN (SELECT U0."id" FROM "bug_toy" U0)'

上記のsubselでわかるように、重複したレコードが返されますが、これは私が望んでいたものではありません。私の質問は、サブセットを取得する適切な方法は何ですか? (注: 定義による設定では、同じオブジェクトが複数回出現することはありません)

なぜそれがそのように振る舞うかについての説明もいいでしょう。私にとってフィルターは、Pythonの組み込み関数filter()で達成することを意味するからです。つまり、要件を満たす要素を取得します (つまり、要件を満たさない要素を破棄します)。そして、この定義はオブジェクトの導入/複製を許可していないようです。

全体にdistinct()を適用できることはわかっていますが、それでもかなり醜い(そしておそらく実際よりも遅い)クエリになります。

>>> str( subsel.distinct().query )
'SELECT DISTINCT "bug_kid"."id", "bug_kid"."name" FROM "bug_kid" INNER JOIN "bug_toy" ON ("bug_kid"."id" = "bug_toy"."owner_id") WHERE "bug_toy"."id" IN (SELECT U0."id" FROM "bug_toy" U0)'

完全を期すための私のmodels.py

from django.db import models

class Kid(models.Model):
    name = models.CharField(max_length=200)

class Toy(models.Model):
    name = models.CharField(max_length=200)
    owner = models.ForeignKey(Kid, related_name='owns')

編集

@limelight とのチャットの後、私の問題は、filter()が辞書の定義に従って動作することを期待しているということです。つまり、Python またはその他の適切なフレームワーク/言語でどのように機能するかです。

より正確には、設定A = {x,y,z}して呼び出しA.filter( <predicate> )た場合、要素が複製されることはないと思います。ただし、Django の QuerySet では、次のように動作します。

A = {x,y,z}
A.filter( <predicate> )
# now A i.e. = {x,x}

したがって、まず第一に問題は不適切なメソッド名です ( match()のようなものの方がはるかに優れています)。2 つ目は、Django で許可されているよりも効率的なクエリを作成できると思うことです。私はそれについて間違っているかもしれません。少し時間があれば、それが本当かどうかを確認しようとします.

4

2 に答える 2

2

DISTINCT の代わりに GROUP BY (django で注釈を付ける) を使用して、個別の子を取得できます。

toy_owners = Toy.objects.values_list("owner_id", flat=True).distinct()
Kid.objects.only('name').filter(pk__in=toy_owners).annotate(count=Count('owns'))
于 2013-08-26T23:52:58.860 に答える