5

私は次のモデル構造を持っています:

class Container(models.Model):
    pass

class Generic(models.Model):
    name = models.CharacterField(unique=True)
    cont = models.ManyToManyField(Container, null=True)
    # It is possible to have a Generic object not associated with any container, 
    # thats why null=True

class Specific1(Generic):
    ...

class Specific2(Generic):
    ...

...

class SpecificN(Generic):
    ...

Specificたとえば、特定のコンテナと関係のあるすべてのタイプのモデルを取得する必要があります。

そのためのSQLは多かれ少なかれ些細なことですが、それは問題ではありません。残念ながら、私はORM(特にDjangoのORM)での作業経験があまりないため、ここでパターンが欠落している可能性があります。

ブルートフォース方式で行われる場合、-

c = Container.objects.get(name='somename') # this gets me the container
items = c.generic_set.all() 
# this gets me all Generic objects, that are related to the container
# Now what? I need to get to the actual Specific objects, so I need to somehow
# get the type of the underlying Specific object and get it
for item in items:
    spec = getattr(item, item.get_my_specific_type())

これにより、大量のdbヒット(コンテナに関連する汎用レコードごとに1つ)が発生するため、これは明らかにそれを行う方法ではありません。これで、おそらく、SpecificXオブジェクトを直接取得することで実行できます。

s = Specific1.objects.filter(cont__name='somename')
# This gets me all Specific1 objects for the specified container
...
# do it for every Specific type

そうすれば、dbは特定のタイプごとに1回ヒットします(許容できると思います)。

.select_related()はm2m関係では機能しないので、ここではあまり役に立ちません。

繰り返しになりますが、最終結果は、(ジェネリックではなく)SpecificXオブジェクトのコレクションである必要があります。

4

3 に答える 3

2

あなたはすでに2つの簡単な可能性を概説したと思います。Genericに対して単一のフィルタークエリを実行してから、各アイテムをその特定のサブタイプにキャストするか(n + 1クエリになります。ここで、nは返されるアイテムの数です)、または各特定のテーブルに対して個別のクエリを実行します(結果はkになります)。クエリ。ここで、kは特定のタイプの数です)。

これらのどれが実際に速いかを確認することは、実際にベンチマークする価値があります。2つ目は、(おそらく)クエリが少ないため、より良いように見えますが、これらのクエリのそれぞれは、m2m中間テーブルとの結合を実行する必要があります。前者の場合、結合クエリを1つだけ実行し、次に単純なクエリを多数実行します。一部のデータベースバックエンドは、少数のより複雑なクエリよりも、多数の小さなクエリでパフォーマンスが向上します。

2つ目が実際にユースケースで大幅に高速であり、コードをクリーンアップするために追加の作業を行う場合は、すべてを「プリフェッチ」するGenericモデルのカスタムマネージャーメソッドを作成できるはずです。サブタイプテーブルごとに1つのクエリのみを使用して、特定のクエリセットに関連する特定のテーブルからのサブタイプデータ。このスニペットがバルクプリフェッチを使用して一般的な外部キーを最適化する方法と同様です。これにより、最初のオプションのDRYer構文を使用して、2番目のオプションと同じクエリが得られます。

于 2009-10-29T14:39:53.257 に答える
1

完全な答えではありませんが、これを行うことで多数のヒットを回避できます

items= list(items)
for item in items:
    spec = getattr(item, item.get_my_specific_type())

これの代わりに :

for item in items:
    spec = getattr(item, item.get_my_specific_type())

実際、Pythonリストへのキャストを強制することで、djangoormにクエリセット内のすべての要素をロードするように強制します。次に、これを1つのクエリで実行します。

于 2009-10-29T10:55:43.777 に答える
0

I accidentally stubmled upon the following post, which pretty much answers your question :

http://lazypython.blogspot.com/2008/11/timeline-view-in-django.html

于 2009-11-10T08:55:42.040 に答える