4

クエリセットに対して実行し、後で関連テーブルのフィールドで実行しprefetch_related('toppings')たい場合、Django はキャッシュされた情報を無視してデータベース クエリを実行します。filter(spicy=True)これは(メモボックスの下に)文書化されており、別の実行時にすべての形式のキャッシング(select_related()、すでに評価されたクエリセットなど)で発生するようfilter()です。

ただし、(リスト/辞書内包表記などを使用して) クエリセットをループするための Python コードを記述する必要なく、(キャッシュを使用し、データベースにヒットしないで) ローカルでフィルター処理するための、ある種の超秘密の隠された時間節約のショートカットはありますか? 多分何かのようなfilter_locally(spicy=True)

編集:

リスト/内包表記がうまく機能しない理由の 1 つは、リスト/辞書にクエリセット メソッドがないためです。私の場合、第 1 レベルの M2M フィールドtoppingsは最終目標ではなく、関連する第 2 の M2M フィールドを確認する必要があります (これも既にプリフェッチしています)。これはリスト内包表記を使用しても可能ですが、次のようなfilter_locally(spicy=True, origin__country='Spain')理由がある方がはるかに簡単です。

  1. 最小限の労力で多くのレベルの関連フィールドにアクセスできます
  2. 他のクエリセットメソッドを連鎖させることができます
  3. おなじみのものと一貫しているため、読みやすくなっています。filter()
  4. プリフェッチなしを使用して既存のコードを変更filter()し、大きな変更を加えることなくこの最適化を追加する方が簡単です。

しかし、応答から、Djangoにはそのようなサポートはありません:(

4

2 に答える 2

3

You have to write the python code to loop through the queryset (a list/dict comprehension is ideal). All the filter() code knows how to do is add filtering language to the SQL sent to the database. Filtering locally is a totally different problem than filtering remotely, so the solutions to those two separate problems won't be able to share any logic.

A list comprehension one-liner would be pretty straightforward, though; the syntax might not be much more complex than with filter().

于 2013-11-04T20:20:54.610 に答える
1

ブール値でフィルタリングしている場合、リストの理解は非常に簡単です。topping.spicy==True文字列比較などに 交換することもできます。

私は次のようなことをします:

qs = Pizza.objects.all().prefetch_related('toppings')
res = list(qs)

def get_spicy(qs):
    res = list(qs)
    return [pizza  for pizza in res if any(topping.spicy==True for 
                                topping in pizza.toppings.all())]

これは、トッピングのいずれかが辛い場合にピザ オブジェクトを返したい場合です。また、any() を all() に置き換えてすべてをチェックし、この構文で非常に強力なクエリを多数実行することもできます。django でこれを行う簡単な方法がないことに少し驚いています。これらの単純なクエリの多くは、一般的な方法で簡単に実装できるはずです。

上記のコードは、many2many を想定しています。one2one や one2many などの単純な FK リレーションシップで動作するように変更するのは簡単です。

これがお役に立てば幸いです。

于 2013-11-04T21:29:48.287 に答える