django - 计算时间段的平均汇率

标签 django postgresql django-models django-queryset django-aggregation

<分区>

在 Django 中我有类似于这个例子的模型:

class Currency(models.Model):
    name = models.CharField(max_length=3, unique=True)
    full_name = models.CharField(max_length=20)


class ExchangeRate(models.Model):
    currency = models.ForeignKey('Currency')
    start_date = models.DateFiled()
    end_date = models.DateField()
    exchange_rate = models.DecimalField(max_digits=12, decimal_places=4)

让我们简化一下,假设我们只有一种货币,ExchangeRate 表如下所示:

+---------------------+-------------------+------------+------------+---------------+
| currency_from__name | currency_to__name | start_date |  end_date  | exchange_rate |
+---------------------+-------------------+------------+------------+---------------+
|        PLN          |        USD        | 2014-03-01 | 2014-08-01 |    3.00000    |
|        PLN          |        USD        | 2014-08-01 | 2014-12-01 |    6.00000    |
+---------------------+-------------------+------------+------------+---------------+

注意这是简化数学运算的例子!

在这个表中数据密度是每月一次,一个月的有效记录是例如 start_date = 2014.03.01end_date = 2014.04.01,所以 start_date 包含在内,end_date 不包含在内。

我想计算一段时间内的平均汇率:

[2014.06.01 ; 2012.09.01)

意思是:>= 2014.06.01< 2014.09.01

在 Django 中我写:

start_date = date(2014, 6, 1)
end_date = date(2014, 9, 1)

ExchangeRate.objects.all().filter(
        (
            Q(start_date__lt=start_date) & 
            Q(end_date__gt=start_date)
        ) | (
            Q(start_date__gte=start_date) & 
            Q(start_date__lt=end_date) & 
            Q(end_date__gt=start_date) 
        )
).annotate(
    currency_from_name = 'currency_from__name', 
    currency_to_name = 'currency_to__name'
).values(  # GROUP BY
    'currency_from_name',
    'currency_to_name'
).aggregate(
    F('currency_from_name'), 
    F('currency_to_name'), 
    Avg('exchange_rate')
)

在这个查询之后,我收到值 4.5000,从数学原因来看这是正确的,但当您需要注意时间范围时是错误的。
正确答案是 4.000

我只是想出这个解决方案来用这个公式注释额外的列,然后从这个列计算平均值:

https://www.codecogs.com/eqnedit.php?latex=\inline&space;Abs&space;\left&space;(&space;\frac{months&space;\left&space;(&space;greater(ER_{start_date}\&space;,\&space;start_date),&space;smaller(ER_{start_date}\&space;,\&space;end_date)&space;\right&space;)&space;}{months(start_date\&space;,\&space;end_date)}&space;\right&space;)&space;*&space;ER_{exchange_rate}

地点:

我正在使用 9.3 PostgreSQL DBDjango 1.8.4

也许有一个简单的功能?
也许我过于复杂了?

最佳答案

1。 months_between():

create function months_of(interval)
 returns int strict immutable language sql as $$
  select extract(years from $1)::int * 12 + extract(month from $1)::int
$$;

create function months_between(date, date)
 returns int strict immutable language sql as $$
   select months_of(age($1, $2))
$$;

2。 average_weight():

create function average_weight(numeric, date, date, date, date)
 returns numeric(9,2) strict immutable language sql as $$
   select abs(months_between(GREATEST($2, $4), LEAST($3, $5))/months_between($4, $5))*$1
$$;

3。 平均体重:

from django.db.models.aggregates import Func
from django.db.models.fields import FloatField

class AverageWeight(Func):
    function = 'average_weight'

    def __init__(self, *expressions):
        super(AverageWeight, self).__init__(*expressions, output_field=FloatField())

在您看来:

ExchangeRate.objects.all().filter(
        (
            Q(start_date__lt=start_date) & 
            Q(end_date__gt=start_date)
        ) | (
            Q(start_date__gte=start_date) & 
            Q(start_date__lt=end_date) & 
            Q(end_date__gt=start_date) 
        )
).annotate(
    currency_from_name = 'currency_from__name', 
    currency_to_name = 'currency_to__name',
    weight_exchange = AverageWeight(
        F('exchange_rate'),
        start_date,
        end_date,
        F('start_date'),
        F('end_date'),
    )
).values(  # GROUP BY
    'currency_from_name',
    'currency_to_name'
).aggregate(
    F('currency_from_name'), 
    F('currency_to_name'), 
    Avg('weight_exchange')
)

关于django - 计算时间段的平均汇率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32351200/

相关文章:

python - Django Rest Framework View 返回一个空对象

hibernate - ALTER TABLE 添加 ON DELETE CASCADE 语句

Django fixture 失败,显示 "DatabaseError: value too long for type character varying(50)"

Django 版本 1.5 : 'url' requires a non-empty first argument. Django 1.5 中的语法发生了变化

python - SQLAlchemy 还是 psycopg2?

postgresql - 错误 : extra data after last expected column in postgres table

python - Django 管理编码错误

python - Django ImageField.path 在 save 方法中返回没有 upload_to 的路径

django - 如何限制表单页面中的外键选择?

mysql - 将 Django 连接到 MySQL 错误 "Did you install mysqlclient?"