【问题标题】:Django filter with inner query?带有内部查询的Django过滤器?
【发布时间】:2020-07-18 17:00:26
【问题描述】:

基于以下模型:

class OpportunityDetail(models.Model):
    ContactDetail = models.ForeignKey(ContactDetail, on_delete=models.CASCADE, related_name='OpportunityContactDetails')
    Stage = models.CharField(max_length=20, unique = False, choices=stages)

class ProductDetail(models.Model):
    Name = models.CharField(max_length=30, unique = False)
    Amount = models.DecimalField(max_digits=12, decimal_places=2, unique = False)

class ProductItemDetail(models.Model):
    ProductDetail = models.ForeignKey(ProductDetail, on_delete=models.CASCADE, related_name='ProductDetails')
    OpportunityDetail = models.ForeignKey(OpportunityDetail, on_delete=models.CASCADE, related_name='OpportunityDetails')
    ChildrenDetail = models.ForeignKey(ChildrenDetail, on_delete=models.CASCADE, related_name='ChildrenProduct')

当我查询机会时,我通常会这样做:

oppLST = OpportunityDetail.objects.filter(ContactDetail = myCon.id)

但是,我想知道如何获得产品项目的内部查询?在 sql 中我会做类似的事情:

SELECT Id, Stage, (SELECT Id, ProductDetail, ProductDetail.Name FROM ProductItemDetail) FROM OpportunityDetail WHERE ContactDetail = myCon.id

我想知道是否可以在 django 中做这样的事情

【问题讨论】:

  • 是的,可以使用 django 在查询中创建子查询。澄清一下,您希望 SQL 查询的结果在您给出的示例中是什么?
  • @PeterGalfi 在我的模板中我想遍历机会,对于每个我想遍历项目,这样我可以显示一个 opps 列表,并为每个 opp 一个他们的项目列表,是否可以使用查询“django 语言”?我的意思是格式 OpportunityDetail.objects.filter ....

标签: python django django-models django-queryset


【解决方案1】:

有几种方法可以解决此问题,具体取决于您要查找的结果。这是一种可能对您来说已经足够的方法。这不使用 django 子查询,只是通过遍历模型中的外键关系来收集您需要的详细信息:

oppLST = OpportunityDetail.objects.filter(ContactDetail=myCon.id).values(
   'id', 'stage', 
   'OpportunityDetails__id', 
   'OpportunityDetails__ProductDetail__id', 
   'OpportunityDetails__ProductDetail__Name'
)

上面将为您提供字典列表,例如:

[
  {'id': 1, 'stage': 'Stage 1', 'OpportunityDetails__id': 1, 'OpportunityDetails__ProductDetail__id': 1, 'OpportunityDetails__ProductDetail__Name': 'details'},
  {'id': 1, 'stage': 'Stage 1', 'OpportunityDetails__id': 1, 'OpportunityDetails__ProductDetail__id': 2, 'OpportunityDetails__ProductDetail__Name': 'details more'},
  {'id': 1, 'stage': 'Stage 1', 'OpportunityDetails__id': 1, 'OpportunityDetails__ProductDetail__id': 3, 'OpportunityDetails__ProductDetail__Name': 'details three'},
  {'id': 2, 'stage': 'Stage B', 'OpportunityDetails__id': 2, 'OpportunityDetails__ProductDetail__id': 5, 'OpportunityDetails__ProductDetail__Name': 'interesting details'},
 ...
]

你可以拿走这个,然后从中得到你需要的东西。

请注意,您在模型定义中使用“related_name”的方式有点不清楚,并且隐藏了该属性的实际含义和用法。该属性通过外键提供反向访问,并且应该以表明这一点的方式命名。此外,为了防止混淆和可能的错误,模型中的字段名称应该小写,这样您就不会将它们与实际模型名称混淆(例如,ProductDetail 是 ProductItemDetail 的字段还是模型 ProductItemDetail 模型?)。

这里有一个建议:

class OpportunityDetail(models.Model):
    contact_detail = models.ForeignKey(ContactDetail, on_delete=models.CASCADE, related_name='opportunities')
    stage = models.CharField(max_length=20, unique = False, choices=stages)

class ProductDetail(models.Model):
    name = models.CharField(max_length=30, unique = False)
    amount = models.DecimalField(max_digits=12, decimal_places=2, unique = False)

class ProductItemDetail(models.Model):
    product_detail = models.ForeignKey(ProductDetail, on_delete=models.CASCADE, related_name='product_items')
    opportunity_detail = models.ForeignKey(OpportunityDetail, on_delete=models.CASCADE, related_name='product_items')
    children_detail = models.ForeignKey(ChildrenDetail, on_delete=models.CASCADE, related_name='product_items')

通过上述更正,django 查询集变为:

oppLST = OpportunityDetail.objects.filter(contact_detail=myCon.id).values(
   'id', 'stage', 
   'product_items__id', 
   'product_items__product_detail__id', 
   'product_items__product_detail__name'
)

希望这会有所帮助,如果有任何需要澄清的地方,请告诉我。

补充:你在上面的评论中提到你想在模板中使用它。您可以直接在模板中引用相关名称,如下所示:

opportunities = OpportunityDetail.objects.filter(ContactDetail=myCon.id)

模板:

{% for opportunity in opportunities %}
     ...
    {% for product_item in opportunity.product_items %}
        <p>{{ product_item.product_detail.id }}</p>
        <p>{{ product_item.product_detail.name }}</p>
    {% endfor %}
{% endfor %}

这可能是您需要的最简单的东西。在模板中执行此操作而不是在数据到达模板之前使用单个查询执行此操作的性能稍差,但与小型数据集无关。

【讨论】:

    猜你喜欢
    • 2019-08-15
    • 2011-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多