Рассчитать количество дней периодов в году, используя Django (queryset) - postgres

Я пытаюсь понять, как рассчитать общее количество периодов в году в базе данных. Возьмем, к примеру, подсчет общего количества отпусков за год.

Я использую:

Django - 1.11.7
Postgres - 9.4

Вот мои модели.py:

class Leave(models.Model):
    leavedatefrom = models.DateField()
    leavedateto = models.DateField()

Пример для иллюстрации проблемы:

leaves taken in 1 year (01/01/2019 - 31/12/2019)

record 1: (leavedatefrom)01/02/2019 - (leavedateto)05/02/2019 ===> 5 days
record 2: (leavedatefrom)10/05/2019 - (leavedateto)12/05/2019 ===> 3 days

Total days = 5 + 3 = 8 days

Как можно рассчитать в Django количество дней периодов в базе данных в году? В основном я хочу получить 8 дней в приведенном выше примере.


person Axil    schedule 21.05.2019    source источник
comment
Куда вы хотите сохранить результат? У вас уже есть записи?   -  person A. Sarid    schedule 21.05.2019
comment
да в модели - поля: (leavedatefrom и leavedateto)   -  person Axil    schedule 21.05.2019
comment
Отлично. Смотрите мой ответ ниже - надеюсь, он ответит на ваш вопрос.   -  person A. Sarid    schedule 21.05.2019


Ответы (3)


По сути, вы можете сделать запрос, чтобы получить все соответствующие листья за год, используя gte и lte django поиск. Например:

import datetime
leaves = Leave.objects.filter(
    leavedatefrom__gte=datetime.date(2019, 1, 1),
    leavedateto__lte=datetime.date(2019, 12, 31)
)

А затем пройтись по всем листьям и вычислить дельту дней между ними и просуммировать ее в другую переменную:

total_days = 0
for leave in leaves:
    total_days += (leave.leavedateto - leave.leavedatefrom).days
print total_days

См. Как рассчитать количество дней между двумя заданными датами? для получения дополнительных сведений и вариантов расчета диапазонов дат.

EDIT: Одна оптимизация, которую можно сделать, если вы не хотите попадать в БД на каждой итерации, заключается в использовании django values_list():

leaves = Leave.objects.filter(
    leavedatefrom__gte=datetime.date(2019, 1, 1),
    leavedateto__lte=datetime.date(2019, 12, 31)
).values_list('leavedatefrom', 'leavedateto')

total_days = 0
for leavedateto, leavedatefrom in leaves:
    total_days += (leavedateto - leavedatefrom).days
print total_days
person A. Sarid    schedule 21.05.2019
comment
За время итерации он попадет в базу данных N раз. - person JPG; 21.05.2019
comment
Спасибо @JPG. Также можно использовать values_list в запросе и вместо этого просматривать значения. - person A. Sarid; 21.05.2019

Думаю, я немного опоздал. Вы можете получить сумму дней в одном запросе SQL

from django.db.models import F, IntegerField, ExpressionWrapper, Sum

Leave.objects.filter(...).annotate(
    diff_date_in_integer=ExpressionWrapper(F('leavedateto') - F('leavedatefrom'), output_field=IntegerField())
).annotate(
    diff_date_in_days=ExpressionWrapper(F('diff_date_in_integer') / (1000000 * 60 * 60 * 24), output_field=IntegerField())).aggregate(
    sum=Sum('diff_date_in_days'))

В предложении filter(...) можно добавить условия фильтрации, например datetime или user specific data.


Описание

  1. аннотировать разницу между leavedateto и leavedatefrom в целом формате (в diff_date_in_integer аннотированном поле )
  2. Преобразование данных diff_date_in_integer в days
  3. используя функцию aggregate() и функцию Sum() БД, мы находим общее количество дней.
person JPG    schedule 21.05.2019

Ниже приведен наивный подход к получению списка периодов.

Получить все записи об отпусках из системы и для каждой записи узнать период дней.

leaves = Leave.objects.filter(leavedatefrom__gte=datetime.date(2019, 1, 1), leavedateto__lte=datetime.date(2019, 12, 31

for leave in leaves:
    days = (leave.leavedatefrom.date() - leave. leavedateto.date()).days()
    period_list.append(days)
total_leaves = sum(period_list)
person Manu mathew    schedule 21.05.2019