如何合并两个Django查询但保持结果?

问题描述 投票:0回答:1

我有两个问题,都给了我自己一个正确的结果。

我尝试合并它们然后,结果出错了(数字成倍增加)。

    qs2 =  Customer.objects.filter(
                opportunity__turnover__date__range=[start, end]
            ).annotate(
                month=TruncMonth('opportunity__turnover__date')
            ).annotate(
                turnover=Sum(
                    "opportunity__turnover__value", 
                    filter=(
                        Q(opportunity__turnover__type='Project')
                    )
                ),

            ).order_by(
                'name','month'
            ).values('name','month','turnover')     

    qs = Customer.objects.filter(
                project__worklog__day__range=[start, end]
            ).annotate(
                month=TruncMonth('project__worklog__day')
            ).annotate(
                hours=Sum("project__worklog__effort")/60/60,
                hoursBilled=Sum(
                    "project__worklog__effort", 
                    filter=(
                        Q(project__worklog__account__category='Abrechenbar')
                        | Q(project__worklog__account__category='Billable')
                    )
                )/60/60,
            ).order_by(
                'name','month'
            ).values('name','hours','month','hoursBilled')  

    df = pd.DataFrame(list(qs2)).merge(pd.DataFrame(list(qs)))

目前我正在将这两个结果转换为Pandas Dataframes并将它们合并 - 这可行但不好,因为我不需要它成为数据帧。

相关模型如下所示:

class Opportunity(models.Model):
    id = models.IntegerField(primary_key=True) #CRMID
    customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
    probability = models.FloatField(null=True, blank=True, default=None)
    closeDate = models.DateField(null=True, blank=True, default=None)
    duration = models.IntegerField()
    value = models.FloatField(null=True, blank=True, default=None)
    name = models.CharField(max_length=200, null=False, blank=False)
    type = models.CharField(max_length=100, null=True, blank=True)
class Turnover(models.Model):
    opportunity = models.ForeignKey(Opportunity, on_delete=models.CASCADE)
    type = models.CharField(max_length=100)
    date = models.DateField(null=True, blank=True, default=None)
    value = models.FloatField(null=True, blank=True, default=None)
class Worklog(models.Model):
    worker = models.ForeignKey(Person, on_delete=models.CASCADE)
    day = models.DateField(null=True, blank=True, default=None)
    effort = models.FloatField() #timeSpentSeconds
    account = models.ForeignKey(Account, on_delete=models.CASCADE, null=True, blank=True)
    comment = models.TextField(null=True)
    project = models.ForeignKey(Project, on_delete=models.CASCADE)
    issue = models.CharField(max_length=200)
class Project(models.Model):
    key = models.CharField(max_length=200, primary_key=True)
    name = models.CharField(max_length=200, null=False, blank=False)
    customer = models.ForeignKey(Customer, on_delete=models.CASCADE, null=True) #this has to come via project category description field 
class Customer(models.Model):
    id = models.IntegerField(primary_key=True) #CRMID
    name = models.CharField(max_length=200, null=True, blank=True, default=None)

这是我在一个查询集中包含所有内容的当前状态:

    qs3 = Customer.objects.filter(
                Q(project__worklog__day__range=[start, end])
                | Q(opportunity__turnover__date__range=[start, end])
            ).annotate(
                month=TruncMonth('project__worklog__day'),
                monthOpp=TruncMonth('opportunity__turnover__date')
            ).filter(
                month=F('monthOpp')
            ).annotate(
                turnover=Sum(
                    "opportunity__turnover__value", 
                    filter=(
                        Q(opportunity__turnover__type='Project')
                    )
                ),
                hours=Sum("project__worklog__effort")/60/60,
                hoursBilled=Sum(
                    "project__worklog__effort", 
                    filter=(
                        Q(project__worklog__account__category='Abrechenbar')
                        | Q(project__worklog__account__category='Billable')
                    )
                )/60/60,
            ).order_by(
                'name','month'
            ).values('name','hours','month','hoursBilled','turnover')  

我得到以下结果:

       hours  hoursBilled       month                                      name     turnover
0    1640.00      1415.00  2019-01-01                       Customer Number ONE     5094288.00
1    1581.67      1482.92  2019-02-01                       Customer Number ONE     5801496.00
2    1117.50      1042.50  2019-03-01                       Customer Number ONE     2226822.72
3     911.67       557.92  2019-04-01                       Customer Number ONE     1395000.00
4   20749.22     14487.72  2019-01-01                       Customer The Second   128129544.48
5   15762.83     14163.33  2019-02-01                       Customer The Second   194805059.94
6   15550.50     12145.00  2019-03-01                       Customer The Second    79077900.00
7     525.00       525.00  2019-04-01                       Customer The Second      190400.00

但是会期待这个结果:

      hours  hoursBilled       month                                      name     turnover
0    328.00       283.00  2019-01-01                       Customer Number ONE       33961.92
1    316.33       296.58  2019-02-01                       Customer Number ONE       35592.00
2    223.50       208.50  2019-03-01                       Customer Number ONE       25020.48
3    182.33       111.58  2019-04-01                       Customer Number ONE       15500.00
4   1482.09      1034.84  2019-01-01                       Customer The Second       99479.46
5   1125.92      1011.67  2019-02-01                       Customer The Second      248793.18
6   1110.75       867.50  2019-03-01                       Customer The Second      102300.00
7     37.50        37.50  2019-04-01                       Customer The Second        5440.00

挑战在于需要考虑两个日期:

project__worklog__dayopportunity__turnover__date

预期结果是所有客户的列表,其中包含每月工作日记的相关总和以及该月的营业额。

理想情况下填写“缺失”月份,因此每个客户都可以填写1月,2月,3月,4月即使客户在2月和3月没有营业额或工作日志 - 但我目前的询问还没有这样做。

谢谢!

django django-orm
1个回答
0
投票

你可以使用|像这样的运营商:

merged = qs | qs2

如果这不起作用,您可以手动构建它:

merged = []

for obj in qs:
    merged.append(obj)

for element in qs2:
    merged.append(qs2)

现在你可以循环了

for item in merged:
    print(item)

这是一个可以完成所有工作的功能

def merge(list_of_querysets)
    return [element for queryset in list_of_querysets for element in queryset]

merged = merge([qs, qs2])
© www.soinside.com 2019 - 2024. All rights reserved.