Reputation: 2017
I have a slow-running Django ListView on a complaints management app I wrote. It's running slow because, when using the ORM, it doesn't hit the database very efficiently.
I've written the following query, which gets the information I need efficiently:
WITH triages AS (
SELECT
agreed_resolution_date
, complaint_id
, date_completed
, id
, stage_id
, MAX(id) OVER(PARTITION BY complaint_id, stage_id) AS ltst
FROM complaints_triage
)
SELECT
cpt.id
, cplnt.first_name || ' ' || cplnt.last_name AS complainant
, DATE_PART('year', cs.date_case_received) AS case_year
, cs.case_reference AS case_reference
, CASE WHEN cpt.handler_id IS NULL
THEN NULL
ELSE usr.first_name || ' ' || usr.last_name
END AS complaint_handler
, tm.name AS team
, stg.stage AS complaint_stage
, CASE WHEN trg.agreed_resolution_date IS NULL
THEN ((cpt.date_received + integer '5') - CURRENT_DATE)
ELSE (trg.agreed_resolution_date - CURRENT_DATE)
END AS time_left
FROM complaints_complaint AS cpt
INNER JOIN complaints_complainant AS cplnt
ON cpt.complainant_id = cplnt.id
LEFT JOIN complaints_case AS cs
ON cpt.case_id = cs.id
LEFT JOIN auth_user AS usr
ON cpt.handler_id = usr.id
INNER JOIN complaints_stage AS stg
ON cpt.stage_id = stg.id
INNER JOIN community_team AS tm
ON cpt.team_id = tm.id
LEFT JOIN triages AS trg
ON trg.stage_id = cpt.stage_id
AND trg.complaint_id = cpt.id
AND trg.id = trg.ltst
WHERE cpt.date_closed IS NULL
ORDER BY time_left
I would like to use this query to override get_queryset
in the ListView
and use the results as a queryset, with the column headings as the attribute names. But using this query to return results as described in the docs returns a list (using cursor.fetchall
) rather than a queryset. Is there any way to return a queryset from this kind of SQL query? Alternatively, is there another established way to do what I'm trying to?
Upvotes: 2
Views: 470
Reputation: 2017
I eventually settled on using a namedtuple
, which has the great benefit of behaving like a queryset in the template (though obviously without being able to access related items through dot notation). First off I changed my views superclass to TemplateView
to remove any default queryset. I then defined the following extra context
from collections import namedtuple
from django.db import connection
...
class AllLiveComplaintListView(TemplateView):
template_name = 'complaints/complaint_list.html'
def get_context_data(self, *args, **kwargs):
context = super(
AllLiveComplaintListView,
self).get_context_data(**kwargs)
with connection.cursor() as c:
c.execute('''
# SQL query from question removed for brevity
''')
ComplaintRecord = namedtuple('ComplaintRecord', 'complaint_id, complainant, case_year, case_reference, handler, team, complaint_stage, days_left')
context['complaint_list'] = map(ComplaintRecord._make, c.fetchall())
return context
Upvotes: 1