4

このクエリを Django でまとめる手助けが必要です。ここでの例は、要点を絞るために単純化されています。

MyModel(models.Model):
    created = models.DateTimeField()
    user = models.ForeignKey(User)
    data = models.BooleanField()

英語で作成したいクエリは次のようになります。

昨日作成されたデータが False であるすべてのレコードを教えてください。その同じ範囲のデータは、特定のユーザーに対して True として表示されません。

明確でない場合の入力/出力の例を次に示します。

表の値

ID   Created    User    Data

1    1/1/2010   admin   False
2    1/1/2010   joe     True
3    1/1/2010   admin   False
4    1/1/2010   joe     False
5    1/2/2010   joe     False

出力クエリセット

1    1/1/2010   admin   False
3    1/1/2010   admin   False

私が探しているのは、レコード #4 を除外することです。この理由は、指定された範囲「yesterday」では、データがレコード #2 のユーザーに対して 1 回 True として表示されるため、レコード #4 が除外されるためです。

ある意味では、2 つのクエリが実行されているように見えます。1 つは指定された範囲内のレコードを決定するためのもので、もう 1 つは「True」レコードと交差するレコードを除外するためのものです。

Django ORM でこのクエリを実行するにはどうすればよいですか?

4

3 に答える 3

6

ネストされたクエリは必要ありません。悪いユーザーの PK のリストを生成し、次のクエリでそれらの PK を含むレコードを除外できます。

bad = list(set(MyModel.obejcts.filter(data=True).values_list('user', flat=True)))
# list(set(list_object)) will remove duplicates
# not needed but might save the DB some work

rs = MyModel.objects.filter(datequery).exclude(user__pk__in=bad)
# might not need the pk in user__pk__in - try it

これを 1 行に要約することもできますが、これで十分だと思います。2 クエリはそれほど悪くありません。

編集:これに関するドキュメントを読みたいかもしれません:

http://docs.djangoproject.com/en/dev/ref/models/querysets/#in

次のような場合、クエリを自動ネストするように聞こえます(したがって、データベースで1つのクエリのみが起動します)。

bad = MyModel.objects.filter(data=True).values('pk')
rs  = MyModel.objects.filter(datequery).exclude(user__pk__in=bad)

しかし、 MySQL はこれを適切に最適化しないため、上記のコード (2 つの完全なクエリ) は実際にははるかに高速に実行される可能性があります。

両方試して、レースをしましょう!

于 2010-03-01T22:55:53.790 に答える
0

遅延評価のおかげで、クエリをいくつかの異なる変数に分割して読みやすくすることができます。これは./manage.py shell、Oli が既に提示したスタイルでの遊びの時間です。

> from django.db import connection
> connection.queries = []
> target_day_qs = MyModel.objects.filter(created='2010-1-1')
> bad_users = target_day_qs.filter(data=True).values('user')
> result = target_day_qs.exclude(user__in=bad_users)
> [r.id for r in result]
[1, 3]
> len(connection.queries)
1

result.select_related()同じクエリでユーザー オブジェクトを取得したい場合にも言えます。

于 2010-03-01T23:56:40.963 に答える
0

あなたが使用できるように見えます: from django.db.models import F MyModel.objects.filter(datequery).filter(data=False).filter(data = F('data'))

Fバージョンから利用可能なオブジェクト1.0

テストしてください、よくわかりません。

于 2010-03-01T23:25:45.880 に答える