Skip to content
Snippets Groups Projects
Commit 47ca62ef authored by Piotr Gawron's avatar Piotr Gawron
Browse files

lazy loading with sorting and filtering (only by string fields)

parent 26523ed0
No related branches found
No related tags found
1 merge request!34Performance of subject list
......@@ -24,4 +24,5 @@ urlpatterns = [
url(r'^units$', api_views.units, name='web.api.units'),
url(r'^referrals$', api_views.referrals, name='web.api.referrals'),
url(r'^appointment_types$', api_views.appointment_types, name='web.api.appointment_types'),
url(r'^subjects/(?P<type>[A-z]+)$', api_views.subjects, name='web.api.subjects'),
]
import json
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse
from models import Subject, Worker, AppointmentType
from views.subject import SUBJECT_LIST_GENERIC
@login_required
......@@ -44,6 +47,131 @@ def units(request):
})
@login_required
def get_subjects(request, type):
if type == SUBJECT_LIST_GENERIC:
return Subject.objects.all()
else:
raise TypeError("Unknown query type: " + type)
def get_subjects_order(subjects, order_column, order_direction):
result = subjects
if order_direction == "asc":
order_direction = ""
else:
order_direction = "-"
if order_column == "first_name":
result = subjects.order_by(order_direction + 'first_name')
elif order_column == "last_name":
result = subjects.order_by(order_direction + 'last_name')
elif order_column == "nd_number":
result = subjects.order_by(order_direction + 'nd_number')
elif order_column == "screening_number":
result = subjects.order_by(order_direction + 'screening_number')
elif order_column == "default_location":
result = subjects.order_by(order_direction + 'default_location')
elif order_column == "dead":
result = subjects.order_by(order_direction + 'dead')
elif order_column == "resigned":
result = subjects.order_by(order_direction + 'resigned')
elif order_column == "postponed":
result = subjects.order_by(order_direction + 'postponed')
return result
def get_subjects_filtered(subjects, filters):
result = subjects
for row in filters:
column = row[0]
value = row[1]
if column == "first_name":
result = result.filter(first_name__contains=value)
elif column == "last_name":
result = result.filter(last_name__contains=value)
elif column == "nd_number":
result = result.filter(nd_number__contains=value)
elif column == "screening_number":
result = result.filter(screening_number__contains=value)
else:
print row
# elif order_column == "default_location":
# result = subjects.order_by(order_direction + 'default_location')
# elif order_column == "dead":
# result = subjects.order_by(order_direction + 'dead')
# elif order_column == "resigned":
# result = subjects.order_by(order_direction + 'resigned')
# elif order_column == "postponed":
# result = subjects.order_by(order_direction + 'postponed')
return result
@login_required
def subjects(request, type):
# id of the query from dataTable: https://datatables.net/manual/server-side
draw = int(request.GET.get("draw", "-1"))
start = int(request.GET.get("start", "0"))
length = int(request.GET.get("length", "10"))
order = int(request.GET.get("order[0][column]", "0"))
order_dir = request.GET.get("order[0][dir]", "asc")
order_column = request.GET.get("columns[" + str(order) + "][data]", "last_name")
filters = []
column_id = 0
while request.GET.get("columns[" + str(column_id) + "][search][value]", "unknown") != "unknown":
val = request.GET.get("columns[" + str(column_id) + "][search][value]", "unknown")
if val != "":
filters.append([request.GET.get("columns[" + str(column_id) + "][data]"), val])
column_id += 1
all_subjects = get_subjects(request, type)
count = all_subjects.count()
ordered_subjects = get_subjects_order(all_subjects, order_column, order_dir)
filtered_subjects = get_subjects_filtered(ordered_subjects, filters)
sliced_subjects = filtered_subjects[start:(start + length)]
subjects = sliced_subjects
count_filtered = filtered_subjects.count()
print json.dumps(request.GET, indent=2)
data = []
for subject in subjects:
data.append(serialize_subject(subject))
return JsonResponse({
"draw": draw,
"recordsTotal": count,
"recordsFiltered": count_filtered,
"data": data,
})
def serialize_subject(subject):
location = ""
if subject.default_location is not None:
location = subject.default_location.name
result = {
"first_name": subject.first_name,
"last_name": subject.last_name,
"nd_number": subject.nd_number,
"screening_number": subject.screening_number,
"default_location": location,
"dead": subject.dead,
"resigned": subject.resigned,
"postponed": subject.postponed,
}
return result
@login_required
def appointment_types(request):
appointments = AppointmentType.objects.filter().all()
......
......@@ -3,7 +3,7 @@
{% block styles %}
{{ block.super }}
{% include "includes/tablesorter.css.html" %}
<link rel="stylesheet" href="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.css' %}">
{% endblock styles %}
{% block ui_active_tab %}'subjects'{% endblock ui_active_tab %}
......@@ -26,78 +26,80 @@
</div>
<div class="box-body">
{% if subjects_list %}
<table id="table" class="table table-bordered table-striped tablesorter">
<thead>
<tr>
<th>ND</th>
<th>Screening</th>
<th>First name</th>
<th>Last name</th>
<th class="filter-select filter-exact" data-placeholder="Select location">Default location</th>
<th>Deceased</th>
<th>Resigned</th>
<th>Postponed</th>
<th>Edit</th>
</tr>
</thead>
{% include "includes/tablesorter.tfoot.html" %}
<tbody>
{% for subject in subjects_list %}
<tr>
<td>{{ subject.nd_number }}</td>
<td>{{ subject.screening_number }}</td>
<td>{{ subject.first_name }}</td>
<td>{{ subject.last_name }}</td>
<td>{{ subject.default_location }}</td>
<td>{% if subject.dead %} YES {% else %} NO {% endif %} </td>
<td>{% if subject.resigned %} YES {% else %} NO {% endif %} </td>
<td>{% if subject.postponed %} YES {% else %} NO {% endif %} </td>
<td><a href="{% url 'web.views.subject_edit' subject.id %}" type="button"
class="btn btn-block btn-default">Edit</a></td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>No subjects found.</p>
{% endif %}
<table id="table" class="table table-bordered table-striped">
<thead>
<tr>
<th>
<div name="string_filter">ND</div>
ND
</th>
<th>
<div name="string_filter">Screening number</div>
Screening
</th>
<th>
<div name="string_filter">Name</div>
First name
</th>
<th>
<div name="string_filter">Surname</div>
Last name
</th>
<th>Default location</th>
<th>Deceased</th>
<th>Resigned</th>
<th>Postponed</th>
<th>Edit</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
{% endblock maincontent %}
{% block scripts %}
{{ block.super }}
{% include "includes/tablesorter.js.html" %}
<script src="{% static 'AdminLTE/plugins/datatables/jquery.dataTables.min.js' %}"></script>
<script src="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.min.js' %}"></script>
<script>
$('#table thead div[name="string_filter"]').each(function () {
var title = $(this).text();
$(this).html('<input type="text" placeholder="Search ' + title + '" />');
});
$(function () {
$('#table').tablesorter({
theme: "bootstrap",
widthFixed: true,
headerTemplate: '{content} {icon}',
widgets: ["uitheme", "filter", "columns", "zebra"],
widgetOptions: {
zebra: ["even", "odd"],
columns: ["primary", "secondary", "tertiary"],
filter_reset: ".reset",
filter_cssFilter: "form-control",
},
headers: {
0: {sorter: true},
}
}).tablesorterPager({
container: $(".ts-pager"),
cssGoto: ".pagenum",
// remove rows from the table to speed up the sort of large tables.
// setting this to false, only hides the non-visible rows; needed if you plan to add/remove rows with the pager enabled.
removeRows: false,
// output string - default is '{page}/{totalPages}';
// possible variables: {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows}
output: '{startRow} - {endRow} / {filteredRows} ({totalRows})'
var table = $('#table').DataTable({
serverSide: true,
processing: true,
ajax: "{% url 'web.api.subjects' list_type %}",
columns: [
{"data": "nd_number"},
{"data": "screening_number"},
{"data": "first_name"},
{"data": "last_name"},
{"data": "default_location"},
{"data": "dead"},
{"data": "resigned"},
{"data": "postponed"}
]
});
// Apply the search
table.columns().every(function () {
var that = this;
$('input', this.header()).on('keyup change', function () {
if (that.search() !== this.value) {
that
.search(this.value)
.draw();
}
});
});
});
</script>
......
......@@ -7,11 +7,13 @@ from . import wrap_response
from ..forms import SubjectAddForm, SubjectEditForm, VisitDetailForm, get_prefix_screening_number
from ..models import Subject, Worker
SUBJECT_LIST_GENERIC = "GENERIC"
def subjects(request):
subjects_list = Subject.objects.order_by('-last_name')
context = {
'subjects_list': subjects_list
'subjects_list': subjects_list,
'list_type': SUBJECT_LIST_GENERIC,
}
return wrap_response(request, 'subjects/index.html', context)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment