【问题标题】:Django - How to exclude instances in queryset due to foreign key model relationDjango - 由于外键模型关系,如何在查询集中排除实例
【发布时间】:2020-07-18 13:43:59
【问题描述】:

如果有任何项目实例不在某个项目列表中,我正在尝试过滤掉报价模型中的实例。从 ProjectItem 模型中检索特定的项目列表。模型结构如下,代码后我会详细解释。

models.py

class SalesProject(models.Model):
    sales_project_id = models.AutoField(primary_key=True)
    sales_project_name = models.CharField(max_length=100)

class ProjectItem(models.Model):
    project_item_id = models.AutoField(primary_key=True)
    project = models.ForeignKey('SalesProject', related_name='items', on_delete=models.CASCADE)
    item = models.ForeignKey('Item', on_delete=models.CASCADE)
    remarks = models.TextField(max_length=1000)

class Quotation(models.Model):
    quotation_id = models.AutoField(primary_key=True)
    salesProject = models.ForeignKey(
        'SalesProject', related_name='quotations', on_delete=models.CASCADE, null=True, blank=True)
    details = models.TextField(max_length=1000, blank=True, null=True)

class QuotationItem(models.Model):
    quotation_item_id = models.AutoField(primary_key=True)
    item = models.ForeignKey('Item', on_delete=models.CASCADE, null=True, blank=True)
    quotation = models.ForeignKey('Quotation', on_delete=models.CASCADE, related_name='items', null=True, blank=True)
    remarks = models.TextField(max_length=1000)

class Item(models.Model):
    item_id = models.AutoField(primary_key=True)
    item_code = models.CharField(max_length=500, null=True, blank=True)
    item_description = models.TextField(max_length=1000, null=True, blank=True)

首先,我将通过查询当前的 SalesProject 来获得一个 Item 实例的列表。 (其中 project = SalesProject 实例)

items = ProjectItem.objects.filter(project=project).values_list('item', flat=True)

基本上,此项目列表中的 Item 实例是“允许的项目”。我想要返回的是仅包含此列表中的 Item 实例的所有 Quotation 实例(或排除包含此列表之外的 Item 实例的任何 Quotation 实例)。 Quotation 与 Item 的关系是通过 QuotationItem 模型实现的。有什么办法吗?

感谢大家的帮助,请指导我,如果信息不足,请告诉我。

【问题讨论】:

  • Quotation 究竟如何映射到ProjectItem?乍一看,两者只通过Porject连接。

标签: python django


【解决方案1】:

您可以使用以下方式过滤:

Quotation.objects.filter(<b>items__item__projectitem__project=<i>project</i></b>)

您可以使用.distinct() 来确保每个Quotation 对象只返回一次:

Quotation.objects.filter(items__item__projectitem__project=<i>project</i>)<b>.distinct()</b>

如果您希望Quotations 引用project,您可以使用.exclude(…),或者更直接,计算Projects:

from django.db.models import Count, Q

Quotation.objects.annotate(
    nproject=Count('items__item__projectitem__project', distinct=True),
    nproject_project=Count(
        'items__item__projectitem__project',
        distinct=True,
        filter=Q(items__item__projectitem__project=project)
    ),
).filter(
    nproject_project=1,
    nproject=1
).distinct()

注意:您的QuotationItem 模型基本上就像ManyToManyField [Django-doc]through 模型, 您可能想添加一个ManyToManyField,此模型为through=… parameter [Django-doc]。 这使得使用 Django ORM 查询此类关系更加方便。

【讨论】:

  • 谢谢,成功了!但是我可以检查一下,您是如何在过滤器查询中获得 projectitem 的?它是默认使用的反向名称吗? (Item到ProjectItem的关系)
  • @jason: 通常使用Quotation.objects.exclude(~Q(items__item__projectitem__project=project)).filter(items__item__projectitem__project=project)(您可以在其中导入Qfrom django.db.models import Q)。
  • @jason:它是条件的否定,所以我们要排除所有引用项目的对象。跨度>
  • @jason:本身不是,因为例如可能根本没有QuotationItem,在这种情况下,排除不会排除它。
  • @jason:您也可以使用聚合,请参阅编辑。
猜你喜欢
  • 2020-05-10
  • 2020-04-20
  • 2017-03-29
  • 2011-12-06
  • 2012-10-10
  • 2020-01-02
  • 1970-01-01
  • 2022-11-22
  • 2018-11-21
相关资源
最近更新 更多