Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Django queryset:如何排除任何相关对象满足条件的对象_Python_Django_Postgresql - Fatal编程技术网

Python Django queryset:如何排除任何相关对象满足条件的对象

Python Django queryset:如何排除任何相关对象满足条件的对象,python,django,postgresql,Python,Django,Postgresql,在进行一个困难的查询时,我偶然发现django QuerySet的一个奇怪行为,我想知道是否有人知道如何改进这个查询 基本上我有一个这样的模型: class Product(models.Model): pass class Stock(models.Model): product_id = models.ForeignKey(Product) date = models.DateField() initial_stock = models.SmallInteg

在进行一个困难的查询时,我偶然发现django QuerySet的一个奇怪行为,我想知道是否有人知道如何改进这个查询

基本上我有一个这样的模型:

class Product(models.Model):
    pass

class Stock(models.Model):
    product_id = models.ForeignKey(Product)
    date = models.DateField()
    initial_stock = models.SmallIntegerField()
    num_ordered = models.SmallIntegerField()
我想选择所有在任何日期都不可用的产品,这意味着没有与产品相关的库存对象的初始库存字段大于num\u ordered字段。所以一开始,我做了:

Product.objects.exclude(stock__initial_stock__gt=F('stock__num_ordered')).distinct()
但我检查了一下,这个查询翻译为:

SELECT DISTINCT *
FROM "product"
LEFT OUTER JOIN "stock"
ON ("product"."id" = "stock"."product_id")
WHERE NOT ("product"."id" IN (
    SELECT U1."product_id" AS Col1 
    FROM "product" U0 
    INNER JOIN "stock" U1 
    ON (U0."id" = U1."product_id") 
    WHERE (U1."initial_stock" > (U1."num_ordered") AND U1."id" = ("stock"."id"))
))
SELECT *
FROM "product"
LEFT OUTER JOIN "stock"
ON ("product"."id" = "stock"."product_id")
LEFT OUTER JOIN "stock" T3
ON ("product"."id" = T3."product_id")
WHERE NOT ("product"."id" IN (
    SELECT U1."product_id" AS Col1 
    FROM "product" U0 
    INNER JOIN "stock" U1 
    ON (U0."id" = U1."product_id") 
    WHERE (U1."initial_stock" > (U1."num_ordered") AND U1."id" = ("stock"."id"))    )
)) AND NOT ("product"."id" IN (
    SELECT U1."product_id" AS Col1 
    FROM "product" U0 
    INNER JOIN "stock" U1 
    ON (U0."id" = U1."product_id") 
    WHERE U1."initial_stock" > (U1."num_ordered"))
))
它在stock上进行左连接,然后过滤掉初始库存大于订购数量的行,然后将不同的行返回给我

如你所见,当我有一个缺货的库存对象和另一个没有缺货的库存对象时,它不起作用

在过滤之后,我被遗漏了一个在另一个日期实际可用的产品

经过多次尝试,我认为这是可行的:

Product.objects.exclude(
    stock__initial_stock__gt=F('stock__num_ordered')
).exclude(
    stock__initial_stock__gt=F('stock__num_ordered')
).distinct()
因为它的意思是:

SELECT DISTINCT *
FROM "product"
LEFT OUTER JOIN "stock"
ON ("product"."id" = "stock"."product_id")
WHERE NOT ("product"."id" IN (
    SELECT U1."product_id" AS Col1 
    FROM "product" U0 
    INNER JOIN "stock" U1 
    ON (U0."id" = U1."product_id") 
    WHERE (U1."initial_stock" > (U1."num_ordered") AND U1."id" = ("stock"."id"))
))
SELECT *
FROM "product"
LEFT OUTER JOIN "stock"
ON ("product"."id" = "stock"."product_id")
LEFT OUTER JOIN "stock" T3
ON ("product"."id" = T3."product_id")
WHERE NOT ("product"."id" IN (
    SELECT U1."product_id" AS Col1 
    FROM "product" U0 
    INNER JOIN "stock" U1 
    ON (U0."id" = U1."product_id") 
    WHERE (U1."initial_stock" > (U1."num_ordered") AND U1."id" = ("stock"."id"))    )
)) AND NOT ("product"."id" IN (
    SELECT U1."product_id" AS Col1 
    FROM "product" U0 
    INNER JOIN "stock" U1 
    ON (U0."id" = U1."product_id") 
    WHERE U1."initial_stock" > (U1."num_ordered"))
))
这“有效”,但感觉像一个奇怪的黑客,似乎不是很简单的事情效率

你们有没有遇到过同样的问题,并想出了更好的办法

谢谢

编辑: 感谢@dirkgroten的回答,为了比较,让我写下sql查询结果:

SELECT *,
       EXISTS(
        SELECT *
          FROM "stock" U0
         WHERE (U0."product_id" = ("product"."id") AND U0."initial_stock" > (U0."num_ordered"))
       ) AS "has_stock"
  FROM "product"
 WHERE EXISTS(
        SELECT *
          FROM "stock" U0
         WHERE (U0."product_id" = ("product"."id") AND U0."initial_stock" > (U0."num_ordered"))
       ) = false
这两个查询的执行时间似乎相同,即使您的查询看起来更好。 虽然我很困惑为什么注释的以下过滤器不使用注释创建的列,而不是在WHERE中再次执行查询

关于我的答案,我不明白的是,为什么在一种情况下,有一个额外的过滤器,并且U1.id=stock.id,而在另一种情况下没有。django在queryset API中是否有奇怪的行为

您最好使用一个:

from django.db.models import OuterRef, Exists

in_stock = Stock.objects.filter(
    product_id=OuterRef('pk'), 
    initial_stock__gt=F('num_ordered'))

out_of_stock_products = Product.objects.annotate(has_stock=Exists(in_stock))\
                                       .filter(has_stock=False)