Django ORM:等同于SQL`NOT IN`? “排除”和“ Q”对象不起作用

问题描述 投票:4回答:1

问题

我正在尝试使用Django ORM等效于SQL NOT IN子句,在subselect中提供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)
    time = models.DateTimeField(blank=True, null=True)

我尝试过的事情

我的第一次尝试是使用exclude,但这确实使NOT否定了整个Subquery,而不是所需的NOT IN

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
    )
)

我需要第三个AND子句是AND "view_job_log"."job_number" NOT IN而不是AND NOT (

我也尝试过先进行子选择,因为它是自己的查询,使用exclude,如下所示:

Django equivalent of SQL not in

但是,这会产生相同的问题结果。然后,我尝试了一个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对象的此尝试再次产生以下SQL,但没有NOT IN

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才能完成此任务?

谢谢您阅读本文全文。显式胜于隐式。 :)

python django postgresql django-models django-orm
1个回答
0
投票

您可以试试吗:

JobLog.objects.filter(time__gte=start, time__lte=end, event="delivered").exclude(time__gte=start, event='finished').exclude(time__lte=end, event='finished')
© www.soinside.com 2019 - 2024. All rights reserved.