带有内部查询的 Django 过滤器?

Django filter with inner query?

基于以下模型:

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 子查询,只是通过遍历模型中的外键关系来收集您需要的详细信息:

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 %}

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