Django的`.first()`方法从一个Decimal中去掉第一个数字。

huangapple go评论66阅读模式
英文:

Django .first() method cuts first digit from a Decimal

问题

我在使用QuerySet上的.first()方法时遇到了非常奇怪的行为。在调用该方法后,十进制值的第一个数字被删除。

模型:

class Distributions(models.Model):
    distribution_id = models.AutoField(primary_key=True)
    months_duration = models.IntegerField(blank=True, null=True)
    month = models.IntegerField(blank=True, null=True)
    activity_date = models.DateField(blank=True, null true)
    value_in_percentage = models.DecimalField(
        max_digits=8, decimal_places=4, blank=True, null=True
    )
    value_in_units = models.DecimalField(
        max_digits=16, decimal_places=4, blank=True, null=True
    )
    distribution_type = models.ForeignKey(
        DistributionType, on_delete=models.DO_NOTHING, blank=True, null=True
    )
    area = models.ForeignKey(Area, on_delete=models.DO_NOTHING, blank=True, null=True)
    is_active = models.BooleanField(blank=True, null=True)

月度值:

data = Distributions.objects.all()
monthly_values = data.values("distribution_type_id", "activity_date").annotate(tsum=Sum("value_in_units"))

代码:

def _get_month_value(self, id: int, month_values: QuerySet) -> int:
        print("----------")
        print(month_values)
        print(month_values.filter(id=id).values('tsum'))
        print(month_values.filter(id=id).values('tsum').first())
        print(month_values.filter(id=id).values('tsum')[0])

输出如下:

<QuerySet [{'id': 1, 'tsum': Decimal('519')}, {'id': 3, 'tsum': Decimal('1019')}, 
{'id': 5, 'tsum': Decimal('0')}, {'id': 9, 'tsum': Decimal('0')}]>
<QuerySet [{'tsum': Decimal('519')}]>
{'tsum': Decimal('19')}
{'tsum': Decimal('519')}

如您所见,对于id为1的情况,原始值为519,但在调用first()方法后变成了19。如果我手动使用[0]调用QuerySet的第一个项目,则不会发生这种情况。

有什么可能引起这个问题的想法吗?

提前感谢 Django的`.first()`方法从一个Decimal中去掉第一个数字。

英文:

I am seeing really strange behavior when using .first() method on a QuerySet. After calling the method, first digit from a Decimal value gets cut.

Models:

class Distributions(models.Model):
    distribution_id = models.AutoField(primary_key=True)
    months_duration = models.IntegerField(blank=True, null=True)
    month = models.IntegerField(blank=True, null=True)
    activity_date = models.DateField(blank=True, null=True)
    value_in_percentage = models.DecimalField(
        max_digits=8, decimal_places=4, blank=True, null=True
    )
    value_in_units = models.DecimalField(
        max_digits=16, decimal_places=4, blank=True, null=True
    )
    distribution_type = models.ForeignKey(
        DistributionType, on_delete=models.DO_NOTHING, blank=True, null=True
    )
    area = models.ForeignKey(Area, on_delete=models.DO_NOTHING, blank=True, null=True)
    is_active = models.BooleanField(blank=True, null=True)

Monthly values:

data = Distributions.objects.all()
monthly_values = data.values(&quot;distribution_type_id&quot;, &quot;activity_date&quot;).annotate(tsum=Sum(&quot;value_in_units&quot;))

Code:

def _get_month_value(self, id: int, month_values: QuerySet) -&gt; int:
        print(&quot;----------&quot;)
        print(month_values)
        print(month_values.filter(id=id).values(&#39;tsum&#39;))
        print(month_values.filter(id=id).values(&#39;tsum&#39;).first())
        print(month_values.filter(id=id).values(&#39;tsum&#39;)[0])

The outputs are as follows:

&lt;QuerySet [{&#39;id&#39;: 1, &#39;tsum&#39;: Decimal(&#39;519&#39;)}, {&#39;id&#39;: 3, &#39;tsum&#39;: Decimal(&#39;1019&#39;)}, 
{&#39;id&#39;: 5, &#39;tsum&#39;: Decimal(&#39;0&#39;)}, {&#39;id&#39;: 9, &#39;tsum&#39;: Decimal(&#39;0&#39;)}]&gt;
&lt;QuerySet [{&#39;tsum&#39;: Decimal(&#39;519&#39;)}]&gt;
{&#39;tsum&#39;: Decimal(&#39;19&#39;)}
{&#39;tsum&#39;: Decimal(&#39;519&#39;)}

As you can see for id 1 the original value is 519 but after I call the first() method it gets turned into a 19. This does not happend if I manually call the first item in QueySet using [0].

Any idea what might be causing this issue?

Thanks in advance Django的`.first()`方法从一个Decimal中去掉第一个数字。

答案1

得分: 1

问题在于函数 first 在 SQL 查询中使用了 FIRST、TOP 或 LIMIT,并且在 SELECT 语句中使用了 SUM。

Django 仅在您需要该值时执行查询,因此 first() 执行整个查询并筛选用于求和的元素。

您可以使用 print(queryset.query) 查看 SQL 查询。

在您的代码中,SQL 查询是 SELECT CAST(SUM("app_distributions"."value_in_units") AS NUMERIC) AS "tsum" FROM "app_distributions" WHERE "app_distributions"."id" = N GROUP BY "app_distributions"."distribution_type_id" "app_distributions"."activity_date"(或类似的查询),当您使用 first() 时,Django 会添加更多的 SQL 并仅获取第一条记录,然后仅对此记录进行求和。

英文:

the problem is that the function first use FIRST, TOP, or LIMIT in SQL query and SUM in the select.

Django executes the query only when you need the value, so the first() executes all the query and filters elements that the sum uses.

You can see de sql query with print(queryset.query).

In your code, the sql is SELECT CAST(SUM(&quot;app_distributions&quot;.&quot;value_in_units&quot;) AS NUMERIC) AS &quot;tsum&quot; FROM &quot;app_distributions&quot; WHERE &quot;app_distributions&quot;.&quot;id&quot; = N GROUP BY &quot;app_distributions&quot;.&quot;distribution_type_id&quot; &quot;app_distributions&quot;.&quot;activity_date&quot; (or similar), and when you use first(), django add more sql and only get the first record and sum only this record.

huangapple
  • 本文由 发表于 2023年2月27日 19:16:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/75579766.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定