Python “接收”;第条中缺少“;django查询中的编程错误

Python “接收”;第条中缺少“;django查询中的编程错误,python,django,postgresql,orm,Python,Django,Postgresql,Orm,我正在尝试编写一个查询,它检索所有订阅,这些订阅的所有者应该被通知其到期 我想排除已通知的订阅和有更新订阅可用的订阅 接下来是查询: Subscription.objects.filter( end_date__gte=timezone.now(), end_date__lte=timezone.now() + timedelta(days=14), ).exclude( Q(notifications__type=Notification.AUTORENEWAL_IN_

我正在尝试编写一个查询,它检索所有订阅,这些订阅的所有者应该被通知其到期

我想排除已通知的订阅和有更新订阅可用的订阅

接下来是查询:

Subscription.objects.filter(
    end_date__gte=timezone.now(),
    end_date__lte=timezone.now() + timedelta(days=14),
).exclude(
    Q(notifications__type=Notification.AUTORENEWAL_IN_14) | Q(device__subscriptions__start_date__gt=F('start_date'))
)
如果没有
|Q(设备订阅\uuu开始日期\uu gt=F('开始日期')
部分,则查询工作正常。有了它,django(postgres)会引发下一个错误:

django.db.utils.ProgrammingError: missing FROM-clause entry for table "u1"
LINE 1: ...ption" U0 INNER JOIN "orders_subscription" U2 ON (U1."id" = ...
我检查了sql,它似乎不正确:

SELECT "orders_subscription"."id",
       "orders_subscription"."months",
       "orders_subscription"."end_date",
       "orders_subscription"."start_date",
       "orders_subscription"."order_id",
       "orders_subscription"."device_id",
FROM "orders_subscription"
WHERE ("orders_subscription"."churned" = false
       AND "orders_subscription"."end_date" >= '2019-04-05T13:27:39.808393+00:00'::timestamptz
       AND "orders_subscription"."end_date" <= '2019-04-19T13:27:39.808412+00:00'::timestamptz
       AND NOT (("orders_subscription"."id" IN
                   (SELECT U1."subscription_id"
                    FROM "notifications_notification" U1
                    WHERE (U1."type" = 'AUTORENEWAL_IN_2W'
                           AND U1."subscription_id" IS NOT NULL))
                 OR ("orders_subscription"."device_id" IN
                       (SELECT U2."device_id"
                        FROM "orders_subscription" U0
                        INNER JOIN "orders_subscription" U2 ON (U1."id" = U2."device_id")
                        WHERE (U2."start_date" > (U0."start_date")
                               AND U2."device_id" IS NOT NULL))
                     AND "orders_subscription"."device_id" IS NOT NULL)))) LIMIT 21

Execution time: 0.030680s [Database: default]
U1没有在任何地方定义(它在另一个子句中本地定义,但这并不重要

关系模型非常简单,一个设备可以有许多订阅,一个订阅可以有许多(不同的)通知

class Subscription(models.Model):
    end_date = models.DateTimeField(null=True, blank=True)
    start_date = models.DateTimeField(null=True, blank=True)

    device = models.ForeignKey(Device, on_delete=models.SET_NULL, null=True, blank=True, related_name="subscriptions")
    # Other non significatn fields

class Device(models.Model):
    # No relational fields

class Notification(models.Model):
    subscription = models.ForeignKey('orders.Subscription', related_name="notifications", null=True, blank=True, on_delete=models.SET_NULL)
    # Other non significatn fields

因此,我的问题是:我的查询是错误的还是Django ORM查询生成器中的一个bug?

ORM显然无法将您的子句转换为SQL。即使该子句单独使用(没有前面的子句,即查询中的任何地方都没有
U1
别名),也会发生这种情况

除了不存在的别名外,ORM似乎还错误识别了
F(“开始日期”)
——它是主
订单订阅(没有别名的订阅),而不是子选择中的任何别名表

您可以通过自己定义适当的子查询来帮助ORM

(以下尝试基于以下假设,即本条款的目的是排除具有更晚日期的同级订阅(=相同的父设备)的订阅。)

下面是带有更正子句的排除过滤器:

from django.db.models import OuterRef, Subquery

qs.exclude(
    Q(notifications__type=Notification.AUTORENEWAL_IN_14) |
    Q(device_id__in=Subquery(Subscription.objects
        .filter(
            device_id=OuterRef('device_id'), 
            start_date__gt=OuterRef('start_date'))
        .values('device_id')
    ))
)
但是,更仔细地观察过滤器,我们正在选择一列(
device\u id
),其值刚刚作为过滤条件传递。这可以通过子查询更好地表达:

from django.db.models import OuterRef, Exists

(qs.annotate(has_younger_siblings=Exists(Subscription.objects.filter(
            device_id=OuterRef('device_id'), 
            start_date__gt=OuterRef('start_date'))))
  .exclude(has_younger_siblings=True)
  .exclude(notifications__type=Notification.AUTORENEWAL_IN_14)
)

发布您的模型您可以共享Django版本吗?
U1
在您提到的问题区域中不可用。您需要找到一种方法在第二个查询中加入
notification\u notification
。@c.grey我在底部添加了模型。@Karioki Django版本为2.1.3
from django.db.models import OuterRef, Exists

(qs.annotate(has_younger_siblings=Exists(Subscription.objects.filter(
            device_id=OuterRef('device_id'), 
            start_date__gt=OuterRef('start_date'))))
  .exclude(has_younger_siblings=True)
  .exclude(notifications__type=Notification.AUTORENEWAL_IN_14)
)