【问题标题】:Django - Filter by related name twice causes duplication of objects in querysetDjango - 按相关名称过滤两次导致查询集中的对象重复
【发布时间】:2020-06-13 13:30:54
【问题描述】:

我在使用related_name 进行过滤时遇到问题。

这是我的代码: 基本上,我首先得到部门并使用它来过滤与客户信息模型具有一对多关系的 LeadSource。但是,当我运行第二个过滤器时,潜在客户的数量会突然从 2 变为 4,或从 3 变为 9(基本上我认为它自己平方,但我不知道为什么)

department = UserProfile.objects.get(user=self.request.user).department
d = department.all()[0]
qs = LeadSource.objects.filter(customers__salesDepartment = d)
print(qs)
qs = qs.filter(customers__created_date__range=(start, end)) # filtering error is from here
print(qs)
qs = qs.annotate(date=TruncMonth('customers__created_date')).values('date', 'source').annotate(count=Count('source')).order_by('date')

这是我的models.py

class CustomerInformation(models.Model):
    customer_id = models.AutoField(primary_key=True)
    customer_name = models.CharField(max_length=100)
    salesDepartment = models.ForeignKey(SalesDepartment, blank=True, null=True, on_delete=models.CASCADE)
    source = models.ForeignKey('LeadSource', related_name='customers', on_delete=models.CASCADE, null=True, blank=True)
    created_date = models.DateField(default=timezone.localdate)

class LeadSource(models.Model):
    source_id = models.AutoField(primary_key=True)
    source = models.CharField(max_length=500)

    def __str__(self):
        return self.source

这是上面两个打印的输出

第一次打印:

<QuerySet [<LeadSource: Facebook>, <LeadSource: Twitter>, <LeadSource: Facebook>, <LeadSource: Instagram>, <LeadSource: Twitter>]>

第二次打印:

<QuerySet [<LeadSource: Facebook>, <LeadSource: Facebook>, <LeadSource: Twitter>, <LeadSource: Twitter>, <LeadSource: Facebook>, <LeadSource: Facebook>, <LeadSource: Twitter>, <LeadSource: Twitter>]>

这是我的最终输出(仅过滤 2020 年 6 月时):

<QuerySet [{'source': 'Facebook', 'date': datetime.date(2020, 6, 1), 'count': 4}, {'source': 'Twitter', 'date': datetime.date(2020, 6, 1), 'count': 4}]>

预期输出(仅过滤 2020 年 6 月时):

<QuerySet [{'source': 'Facebook', 'date': datetime.date(2020, 6, 1), 'count': 2}, {'source': 'Twitter', 'date': datetime.date(2020, 6, 1), 'count': 2}]>

这是我的 CustomerInformation 实例及其所需的详细信息:

ID: 1
Source: Facebook
Date: 2020-06-11

ID: 2
Source: Twitter
Date: 2020-06-12

ID: 3
Source: Facebook
Date: 2020-06-11

ID: 4
Source: Instagram
Date: 2020-01-01

ID: 5
Source: Twitter
Date: 2020-06-13

感谢所有帮助,谢谢!我真的不知道是什么导致了这个错误,但可能是因为我使用了related_name 过滤了两次?

【问题讨论】:

  • 您检查过数据库中的任何数据重复吗?
  • 问题是你在customer 表上做了两个JOIN,每个过滤器一个。您可能想在 same JOIN 中进行过滤?
  • 对不起,我是 django 的新手,但你所说的 JOIN 是什么意思?
  • @jason: 如果你对相关模型进行过滤,它会在数据库中进行 JOIN:en.wikipedia.org/wiki/Join_(SQL)
  • 有没有办法让我使用两个过滤器来做到这一点?我将其拆分的原因是因为有一个 if 语句可以通过 salesDepartment 或其他字段过滤第一个查询。因此它与第二个 JOIN 分开

标签: python django


【解决方案1】:

你在这里做了两个 JOIN,因为你使用了两个独立的.filter()s。但是即使使用单个JOIN,这也可能导致重复记录,因为对于每个customersalesDepartment=d,它都会产生一个结果,这意味着可以多次返回LeadSource(不是本身两次,例如有五个客户salesDepartment=d),会被退回五次。

您可以使用.distinct() [Django-doc] 仅检索唯一记录:

d = UserProfile.objects.get(user=self.request.user).department.first()
qs = LeadSource.objects.filter(
    customers__salesDepartment=d, customers__created_date__range=(start, end)
).distinct()

如果过滤是有条件的,可以使用Q对象:

from django.db.models import Q

d = UserProfile.objects.get(user=self.request.user).department.first()

my_filter = Q(customers_salesDepartment=d)
if some_condition:
    myfilter &= Q(customers__created_date__range=(start, end))

qs = LeadSource.objects.filter(
    my_filter
).distinct()

【讨论】:

  • 我尝试使用 distinct,但它不起作用,因为在这之后我有更多的注释导致相同的结果,我现在将编辑问题以包含过滤后的注释。
  • @jason: 那么这些不是重复的记录,因为TruncMonth 是不同的,所以它返回多条记录是完全合乎逻辑的,因为这基本上就是你要问的......
  • @jason:好吧,如果你每个月都需要它,那么它当然会为每个月返回相同的记录。
  • 我不太关注你,抱歉我是 django 新手,但我总共有 5 个 CustomerInformation 实例(2020 年 1 月 1 个,2020 年 6 月 4 个)。在 2020 年 6 月的 4 个中,有 2 个来源为“Twitter”,2 个来源为“Facebook”。因此,我认为即使截断后我的输出也会被计数:2020 年 6 月,每个来源(Twitter 和 Facebook)都有 2 个。但是,我收到的是每个 4 个,这真的让我感到困惑。
  • @Jason:它将返回(Twitter, January)(Twitter, June)(Facebook, January)(Facebook, June)等的记录。
猜你喜欢
  • 1970-01-01
  • 2015-01-11
  • 2021-01-24
  • 2023-01-16
  • 2021-10-27
  • 1970-01-01
  • 1970-01-01
  • 2011-05-19
  • 2011-04-21
相关资源
最近更新 更多