【问题标题】:Django how to filter a foreign key object only with specific valueDjango如何仅过滤具有特定值的外键对象
【发布时间】:2021-11-04 15:28:27
【问题描述】:

我有两张桌子。 餐桌产品

id | name | 

餐桌折扣

id | product_id | is_deleted

两个模型是:

class Product(models.Model):
    name = models.CharField(max_length=10)

class Discount(models.Modle):
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    is_deleted = models.BooleanField(default=True)

product_id是产品表id的外键,is_deleted是一个布尔字段。 如何仅使用 is_deleted 折扣过滤所有产品?请注意,这两个表可能很大,因此 .exclude() 不适合这种情况。

【问题讨论】:

  • 你能分享你的Django模型吗?
  • 如果Product 有两个(或更多)折扣,并且其中只有一个将is_deleted 设置为True,那么应该排除还是保留?
  • @WillemVanOnsem 添加型号代码。产品和折扣之间没有限制。一种产品可以有多个折扣,这些折扣可以是 is_deleted 也可以不是。我只需要在 is_deleted 设置为 true 的情况下过滤掉所有产品。
  • 那么如果一个产品有两个折扣,一个is_deleted设置为True,一个设置为False,查询集是包含那个产品,还是排除那个产品?
  • 此外,另一个悬而未决的问题是如何处理根本没有任何折扣的Products。

标签: django postgresql django-queryset


【解决方案1】:
product_ids_subquery = Discount.objects.values('product').annotate(
               deleted=(Count('product') - Count('product', filter=Q(is_deleted=True)))
            ).filter(deleted=0).values('product')

products_qs = Product.objects.filter(id__in=product_ids_subquery)

我们可以通过按产品分组后的计数来识别仅具有 is_deleted 折扣的产品。对于每个产品,

  1. 计算折扣表中有多少记录。假设 total_count = Count('product')
  2. 计算有多少记录被删除。假设deleted_count = Count('product', filter=Q(is_deleted=True))
  3. deleted = (total_count - deleted_count) 给你一个不。没有被删除

如果删除 == 0 那么你可以说所有映射的记录都被删除了

【讨论】:

  • 这可能是一个正确的答案,但是如果产品表非常大,当我们尝试在这个 finally 查询集上使用切片时,我不确定 id__in 子句是否会有合理的性能。
  • @TianchengLiu 这里id__in 不是IN 查询基本上是子查询,id 是主键所以性能还不错。如果您只想要 product_ids 则无需运行第二个查询。您可以通过打印print(products_qs.query) 来检查原始查询
  • @joshlsullivan 仅代码答案不太有用。 Stack Overflow 是关于学习的,而不是提供 sn-ps 来盲目复制和粘贴。我在我的review task (LQA) 中评论了这篇文章,作为回应,作者添加了一个解释,这很好。我无法理解你的担忧。请看一些元帖子:meta.stackoverflow.com/a/300846/3749896meta.stackoverflow.com/questions/260411/…
【解决方案2】:
products = Product.objects.filter(discount__is_deleted=True)

【讨论】:

    猜你喜欢
    • 2020-08-28
    • 2021-09-11
    • 1970-01-01
    • 2014-08-19
    • 1970-01-01
    • 1970-01-01
    • 2016-07-12
    • 2017-06-03
    • 1970-01-01
    相关资源
    最近更新 更多