[解決済み] Django filter queryset __in for *every* item in list
2022-07-21 08:43:14
質問
次のようなモデルがあるとします。
class Photo(models.Model):
tags = models.ManyToManyField(Tag)
class Tag(models.Model):
name = models.CharField(max_length=50)
ビューの中で、アクティブなフィルタである カテゴリ . に存在するすべてのタグを持つ写真オブジェクトをフィルタリングしたい。 カテゴリ .
試してみました。
Photo.objects.filter(tags__name__in=categories)
しかし、これは にもマッチします。 にマッチし、カテゴリ内の すべて の項目である。
つまり、カテゴリが ['holiday', 'summer'] の場合、holiday と summer の両方のタグを持つ写真が欲しいのです。
これは実現できるのでしょうか?
どのように解決するのですか?
概要です。
コメントでjpicとsgallenが提案したように、1つのオプションとして
.filter()
を追加することです。それぞれの追加された
filter
を追加するごとに結合が増えますが、これは小さなカテゴリの集合では問題ないでしょう。
には アグリゲーション アプローチ . このクエリは、大きなカテゴリのセットに対してより短く、おそらくより速くなるでしょう。
また カスタムクエリ .
いくつかの例
テストの設定です。
class Photo(models.Model):
tags = models.ManyToManyField('Tag')
class Tag(models.Model):
name = models.CharField(max_length=50)
def __unicode__(self):
return self.name
In [2]: t1 = Tag.objects.create(name='holiday')
In [3]: t2 = Tag.objects.create(name='summer')
In [4]: p = Photo.objects.create()
In [5]: p.tags.add(t1)
In [6]: p.tags.add(t2)
In [7]: p.tags.all()
Out[7]: [<Tag: holiday>, <Tag: summer>]
使用方法 連鎖したフィルタ のアプローチを使用します。
In [8]: Photo.objects.filter(tags=t1).filter(tags=t2)
Out[8]: [<Photo: Photo object>]
結果のクエリ
In [17]: print Photo.objects.filter(tags=t1).filter(tags=t2).query
SELECT "test_photo"."id"
FROM "test_photo"
INNER JOIN "test_photo_tags" ON ("test_photo"."id" = "test_photo_tags"."photo_id")
INNER JOIN "test_photo_tags" T4 ON ("test_photo"."id" = T4."photo_id")
WHERE ("test_photo_tags"."tag_id" = 3 AND T4."tag_id" = 4 )
なお、各
filter
はさらに
JOINS
を追加します。
使用方法 アノテーション アプローチ :
In [29]: from django.db.models import Count
In [30]: Photo.objects.filter(tags__in=[t1, t2]).annotate(num_tags=Count('tags')).filter(num_tags=2)
Out[30]: [<Photo: Photo object>]
結果のクエリ
In [32]: print Photo.objects.filter(tags__in=[t1, t2]).annotate(num_tags=Count('tags')).filter(num_tags=2).query
SELECT "test_photo"."id", COUNT("test_photo_tags"."tag_id") AS "num_tags"
FROM "test_photo"
LEFT OUTER JOIN "test_photo_tags" ON ("test_photo"."id" = "test_photo_tags"."photo_id")
WHERE ("test_photo_tags"."tag_id" IN (3, 4))
GROUP BY "test_photo"."id", "test_photo"."id"
HAVING COUNT("test_photo_tags"."tag_id") = 2
AND
編
Q
オブジェクトは動作しないでしょう。
In [9]: from django.db.models import Q
In [10]: Photo.objects.filter(Q(tags__name='holiday') & Q(tags__name='summer'))
Out[10]: []
In [11]: from operator import and_
In [12]: Photo.objects.filter(reduce(and_, [Q(tags__name='holiday'), Q(tags__name='summer')]))
Out[12]: []
結果のクエリ
In [25]: print Photo.objects.filter(Q(tags__name='holiday') & Q(tags__name='summer')).query
SELECT "test_photo"."id"
FROM "test_photo"
INNER JOIN "test_photo_tags" ON ("test_photo"."id" = "test_photo_tags"."photo_id")
INNER JOIN "test_tag" ON ("test_photo_tags"."tag_id" = "test_tag"."id")
WHERE ("test_tag"."name" = holiday AND "test_tag"."name" = summer )
関連
-
[解決済み】Djangoのクエリセットフィルタリングでnot equalを行うにはどうすればよいですか?
-
[解決済み] リスト内のアイテムのインデックスを検索する
-
[解決済み] リストからランダムに項目を選択するにはどうすればよいですか?
-
[解決済み] リスト項目の出現回数を数えるにはどうしたらいいですか?
-
[解決済み] リスト内包とラムダ+フィルタの比較
-
[解決済み] QuerySetで空白またはNULLの名前をフィルタリングする方法は?
-
[解決済み] Django のクエリで OR フィルタを行うにはどうすればよいですか?
-
[解決済み] Django のクエリを値のリストでフィルタリングするにはどうすればよいですか?
-
[解決済み] django のクエリセットで OR 条件を実行する方法は?
-
[解決済み] あるオブジェクトが数であるかどうかを確認する、最もパイソン的な方法は何でしょうか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] 前月の日時オブジェクトを返す
-
[解決済み] Python 3でバイナリデータを標準出力に書き込むには?
-
[解決済み] ファブリック経由でデプロイユーザとしてvirtualenvを有効化する
-
[解決済み] あるオブジェクトが数であるかどうかを確認する、最もパイソン的な方法は何でしょうか?
-
[解決済み] Pythonでマルチプロセッシングキューを使うには?
-
[解決済み] Python Logging でログメッセージが2回表示される件
-
[解決済み] if 節の終了方法
-
[解決済み] PythonのRequestsモジュールを使ってWebサイトに "ログイン "するには?
-
[解決済み] ImproperlyConfigured: 環境変数 DJANGO_SETTINGS_MODULE を定義するか、設定にアクセスする前に settings.configure() を呼び出す必要があります。
-
[解決済み] 複数のプロットを1つのPDFファイルに保存する