Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django + PostgreSQL: Fill missing dates in a range

I have a table with one of the columns as date. It can have multiple entries for each date.

date         .....
-----------  -----
2015-07-20     ..
2015-07-20     ..
2015-07-23     ..
2015-07-24     ..

I would like to get data in the following form using Django ORM with PostgreSQL as database backend:

date         count(date)
-----------  -----------
2015-07-20        2
2015-07-21        0       (missing after aggregation)
2015-07-22        0       (missing after aggregation)
2015-07-23        1
2015-07-24        1

Corresponding PostgreSQL Query:

WITH RECURSIVE date_view(start_date, end_date) 
AS ( VALUES ('2015-07-20'::date, '2015-07-24'::date) 
     UNION ALL SELECT start_date::date + 1, end_date 
     FROM date_view 
     WHERE start_date < end_date ) 
SELECT start_date, count(date) 
FROM date_view LEFT JOIN my_table ON date=start_date 
GROUP BY date, start_date 
ORDER BY start_date ASC;

I'm having trouble translating this raw query to Django ORM query.

It would be great if someone can give a sample ORM query with/without a workaround for Common Table Expressions using PostgreSQL as database backend.

The simple reason is quoted here:

My preference is to do as much data processing in the database, short of really involved presentation stuff. I don't envy doing this in application code, just as long as it's one trip to the database

As per this answer django doesn't support CTE's natively, but the answer seems quite outdated.

References:

  • MySQL: Select All Dates In a Range Even If No Records Present

  • WITH Queries (Common Table Expressions)

Thanks

like image 534
Ankit Popli Avatar asked Jul 28 '15 17:07

Ankit Popli


1 Answers

I do not think you can do this with pure Django ORM, and I am not even sure if this can be done neatly with extra(). The Django ORM is incredibly good in handling the usual stuff, but for more complex SQL statements and requirements, more so with DBMS specific implementations, it is just not quite there yet. You might have to go lower and down to executing raw SQL directly, or offload that requirement to be done by the application layer.

You can always generate the missing dates using Python, but that will be incredibly slow if the range and number of elements are huge. If this is being requested by AJAX for other use (e.g. charting), then you can offload that to Javascript.

like image 119
Wannabe Coder Avatar answered Sep 19 '22 23:09

Wannabe Coder