记录之间的Django ORM计算

时间:2018-01-17 04:39:01

标签: django pandas django-models django-queryset

是否可以在Django查询中执行 记录之间的计算?

我知道如何在 记录中执行 计算(例如data_a + data_b)。有没有办法说数据_第0行和第4行(即09-30-17和09-30-16)之间的百分比变化?

+-----------+--------+--------+
|   date    | data_a | data_b |
+-----------+--------+--------+
| 09-30-17  |    100 |    200 |
| 06-30-17  |     95 |    220 |
| 03-31-17  |     85 |    205 |
| 12-31-16  |     80 |    215 |
| 09-30-16  |     75 |    195 |
+-----------+--------+--------+

我目前正在使用Pandas来执行这些类型的计算,但如果可能的话,我希望消除这一额外步骤。

2 个答案:

答案 0 :(得分:1)

我会使用Database cursor raw SQL (见https://docs.djangoproject.com/en/2.0/topics/db/sql/

结合滞后()窗口函数,如下所示:

result = cursor.execute("""
    select date, 
       data_a - lag(data_a) over (order by date) as data_change,
from foo;""")

这是一般性的想法,您可能需要根据需要进行更改。

答案 1 :(得分:0)

Django数据库中没有第0行,因此我们假设第1行和第5行。

Python中表示的百分比计算通用公式为:

((b - a) / a) * 100

其中a是起始编号,b是结束编号。所以在你的例子中:

a = 100
b = 75
((b - a) / a) * 100
-25.0

如果您的模型名为Foo,则您需要的查询是:

(a, b) = Foo.objects.filter(id__in=[id_1, id_2]).values_list('data_a', flat=True)

values_list说"得到这些字段"并且flat=True表示您需要一个简单的值列表,而不是键/值对。通过将其分配给(a, b)元组并使用__in=子句,您可以将其作为单个查询而不是两个查询。

我会把它全部包装成一个独立的函数或模型方法:

def pct_change(id_1, id_2):
    # Get a single column from two rows and return percentage of change
    (a, b) = Foo.objects.filter(id__in=[id_1, id_2]).values_list('data_a', flat=True)
    return ((b - a) / a) * 100

然后,如果您知道要比较的两行数据库中的行ID,那么它只是:

print(pct_change(233, 8343))

如果您想逐步计算第1行和第2行之间的变化,然后在第2行和第3行之间进行更改,依此类推,您只需对查询集中的每一行依次运行此函数。由于行ID可能有间隙,因此我们无法使用n + 1来计算下一行。相反,首先获取查询集中所有行ID的列表:

rows = [r.id for r in Foo.objects.all().order_by('date')]

评估为

之类的内容
rows = [1,2,3,5,6,9,13]

现在列表中的每个elem和列表中的下一个elem,运行我们的函数:

for (index, row) in enumerate(rows):
    if index < len(rows):
        current, next_ = row, rows[index + 1]
        print(current, next_)
        print(pct_change(current, next_))