web-dev-qa-db-ja.com

Django ORM:SQLと同等の `NOT IN`?` exclude`および `Q`オブジェクトは機能しません

問題

Django ORMを使用して、SQL _NOT IN_句と同等のことを行い、IDのリストを副選択に提供して、ログから一連のレコードを取得しようとしていますテーブル。これが可能かどうかわかりません。

モデル

_class JobLog(models.Model):
    job_number = models.BigIntegerField(blank=True, null=True)
    name = models.TextField(blank=True, null=True)
    username = models.TextField(blank=True, null=True)
    event = models.TextField(blank=True, null=True)
    time = models.DateTimeField(blank=True, null=True)
_

私が試したこと

私の最初の試みはexcludeを使用することでしたが、これはNOTを使用して、目的の_NOT IN_ではなくSubquery全体を否定します。

_query = (
    JobLog.objects.values(
        "username", "job_number", "name", "time",
    )
    .filter(time__gte=start, time__lte=end, event="delivered")
    .exclude(
        job_number__in=models.Subquery(
            JobLog.objects.values_list("job_number", flat=True).filter(
                time__gte=start, time__lte=end, event="finished",
            )
        )
    )
)
_

残念ながら、これにより次のSQLが生成されます。

_SELECT "view_job_log"."username", "view_job_log"."group", "view_job_log"."job_number", "view_job_log"."name", "view_job_log"."time"
FROM "view_job_log"
WHERE (
    "view_job_log"."event" = 'delivered'
    AND "view_job_log"."time" >= '2020-03-12T11:22:28.300590+00:00'::timestamptz
    AND "view_job_log"."time" <= '2020-03-13T11:22:28.300600+00:00'::timestamptz
    AND NOT (
        "view_job_log"."job_number" IN (
            SELECT U0."job_number"
            FROM "view_job_log" U0
            WHERE (
                U0."event" = 'finished' AND U0."time" >= '2020-03-12T11:22:28.300590+00:00'::timestamptz
                AND U0."time" <= '2020-03-13T11:22:28.300600+00:00'::timestamptz
            )
        )
        AND "view_job_log"."job_number" IS NOT NULL
    )
)
_

3番目のAND句を_AND "view_job_log"."job_number" NOT IN_ではなく_AND NOT (_にする必要があります。

ここで提案されているように、excludeを使用して、最初に独自のクエリとして副選択を実行してみました。

DjangoのSQLに相当しない

ただし、これは同じ問題のある結果をもたらします。次に、Qオブジェクトを試しましたが、同様のクエリが生成されます。

_query = (
    JobLog.objects.values(
        "username", "subscriber_code", "job_number", "name", "time",
    )
    .filter(
        ~models.Q(job_number__in=models.Subquery(
            JobLog.objects.values_list("job_number", flat=True).filter(
                time__gte=start, time__lte=end, event="finished",
            )
        )),
        time__gte=start,
        time__lte=end,
        event="delivered",
    )
)
_

Qオブジェクトを使用したこの試行により、_NOT IN_なしで、次のSQLが再び生成されます。

_SELECT "view_job_log"."username", "view_job_log"."group", "view_job_log"."job_number", "view_job_log"."name", "view_job_log"."time"

FROM "view_job_log" WHERE (
    NOT (
        "view_job_log"."job_number" IN (
            SELECT U0."job_number"
            FROM "view_job_log" U0
            WHERE (
                U0."event" = 'finished'
                AND U0."time" >= '2020-03-12T11:33:28.098653+00:00'::timestamptz
                AND U0."time" <= '2020-03-13T11:33:28.098678+00:00'::timestamptz
            )
        )
        AND "view_job_log"."job_number" IS NOT NULL
    )
    AND "view_job_log"."event" = 'delivered'
    AND "view_job_log"."time" >= '2020-03-12T11:33:28.098653+00:00'::timestamptz
    AND "view_job_log"."time" <= '2020-03-13T11:33:28.098678+00:00'::timestamptz
)
_

DjangoのORMにAND job_number NOT IN (12345, 12346, 12347)と同等の機能を実行させる方法はありますか?それとも、これを達成するために生のSQLにドロップする必要がありますか?

このテキスト全体の質問全体を読んでいただき、ありがとうございます。明示的は暗黙的よりも優れています。 :)

7
FlipperPA

あなたはこれを試すことができます:

JobLog.objects.filter(time__gte=start, time__lte=end, event="delivered").exclude(time__gte=start, event='finished').exclude(time__lte=end, event='finished')
0
Yellowduck