Jquery datatables plugin for django - javascript

I am newbie to django. I am using jquery datatable plugins in my django application. These datatables are working fine for the small datasets sent from my view. I have a django model which is having 65k records with 5 columns. when I am trying to show these records in jquery datatables the rendered page becoming unresponsive for a moment and the page is loading correctly. Also sorting, searching, pagination features are working fine with reasonable to amount of time. I want to see the page responsive even when I am showing 65k entries in datatables. Is there any way to do this? or what will be the best solution to handle large datasets? Pls suggest me
I came to know that this is because I am trying to format datatables on client side after loading 65k records from the server. Also I googled n knew that server side processing will be the best way to handle this. Any one pls suggest me how to do server side processing in django.
Now, my code is as follows:
part of Inventory.html:
<div class="box-body table-responsive" id='postinfo'>
</div>
InventoryOutputAlldata.html:
{% load staticfiles %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script type="text/javascript">
$(function(){
$('#example1').dataTable({
});
});
</script>
</head>
<table id="example1" class="table table-bordered table-hover">
<thead>
<tr>
<th>Device</th>
<th>Device Type</th>
<th>Mac Address</th>
<th>IP Address</th>
<th>Status</th>
</tr>
</thead>
<tbody >
<form name="trform" method="post">
{% for key,value in data.items %}
<tr class="trselected" onclick="trclick(this)">
<td>{{ value.0 }}</td>
<td>{{ value.1 }}</td>
<td>{{ value.2 }}</td>
<td>{{ value.3 }}</td>
<td>{{ value.4 }}</td>
</tr>
{% endfor %}
</form>
</tbody>
<tfoot>
<tr>
<th>Device</th>
<th>Device Type</th>
<th>Mac Address</th>
<th>IP Address</th>
<th>Status</th>
</tr>
</tfoot>
</table>
</html>
JS:
$(function(){
var data = new Object();
data['showdata'] = 'all';
data["csrfmiddlewaretoken"] = $("input[name='csrfmiddlewaretoken']").val();
$( "#postinfo" ).load( "/alldata/", data, function( response, status, xhr )
{
});
});
URLs.py:
urlpatterns = patterns('',
url(r'^inventory/$', TemplateView.as_view(template_name='inventory.html')),
url(r'^alldata/$', 'NetworkInventory.nmap_integration.alldata'),
)
views.py:
def alldata(request):
postedInfo = request.POST
count = 0
dataDict = {}
dbData = nmap.objects.all()
if 'showdata' in postedInfo and postedInfo['showdata'] == 'all':
for data in dbData:
count += 1
dataDict[count] = []
dataDict[count].append(data.device)
dataDict[count].append(data.devicetype)
dataDict[count].append(data.macaddress)
dataDict[count].append(data.ipaddress)
dataDict[count].append(data.status)
else:
return HttpResponse('Improper Behaviour')
return render_to_response('inventoryOutputAlldata.html',{'data': dataDict})
Please suggest me how can i modify this to work with large datasets.

When you do it that way all of the records are loaded into cache. You need to use iterate.
Perhaps this is what you want.
car_set = Car.objects.all()
for car in car_set.iterator():
#Do something
Or more advanced
djangosnippets
Try this
import gc
def queryset_iterator(queryset, chunksize=1000):
'''''
Iterate over a Django Queryset ordered by the primary key
This method loads a maximum of chunksize (default: 1000) rows in it's
memory at the same time while django normally would load all rows in it's
memory. Using the iterator() method only causes it to not preload all the
classes.
Note that the implementation of the iterator does not support ordered query sets.
'''
pk = 0
last_pk = queryset.order_by('-pk')[0].pk
queryset = queryset.order_by('pk')
while pk < last_pk:
for row in queryset.filter(pk__gt=pk)[:chunksize]:
pk = row.pk
yield row
gc.collect()

You can simply use a page loader for this. You can set the page loader to the time taken for your datatable rendered correctly into the page.

Related

Sending data to database with JavaScript in Django

I need to write a compatible algorithm for this code, but I can't. How can I send data to backend?
I am using bootstable.js for table
HTML table:
<table class="table table-bordered" id="table-list">
<thead>
<tr>
<th></th>
<th>Name</th>
<th>Slug</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{% for chart in charts %}
<tr>
<th id="id">{{chart.id}}</th>
<td class="editable" id="name">{{chart.name}}</td>
<td class="editable" id="slug">{{chart.slug}}</td>
<td>john#example.com</td>
</tr>
{% empty %}
<p>No data</p>
{% endfor %}
</tbody>
</table>
And this is my JavaScript code. I tried to try some methods myself but it didn't work
<script src="{% static 'npe_cp/js/bootstable.js' %}"></script>
<script>
//apply
$("#table-list").SetEditable();
$('#addRow').click(function() {
rowAddNew('table-list');
});
$('#bAcep').on('click', function(){
// var id=$("#id").val();
// var name=$("#name-44").val();
// var slug=$("#slug-44").val();
let name=document.querySelector('#name')
console.log(id, name, slug, 'Hello World')
$.ajax({
url:"/chart/edit",
type:"POST",
data:{
"id":id,
"name":name,
"slug":slug,
},
})
});
This is exactly what the table looks like. I want to update, create, and delete operations. But I am not getting the data.
Use Django Forms to populate the database, makes it easy to perform CRUD operations

How do i put the serial number in each table row while using {{#each}} loop in handlebars?

I am creating a table to show list of items from the database, but how do I put the serial No. for the list when using an {{#each}} loop:
<table class="table mt-5">
<thead>
<tr>
<th scope="col">No.</th>
<th scope="col">Title</th>
<th scope="col">Category</th>
<th scope="col">Description</th>
<th>Image</th>
</tr>
</thead>
<tbody>
{{#each products}}
<tr>
<th scope="row">1</th>
<td>{{this.Name}}</td>
<td>{{this.Category}}</td>
<td>{{this.Description}}</td>
<td><img style="width:100px" src="/product-images/{{this._id}}.png" alt="Img"></td>
</tr>
{{/each}}
</tbody>
</table>
This is the table I am using. In the <th> tag I have written 1. I want to replace it with the sl. no. This is an .hbs file and I am using Node.js and MongoDB as database.
How can I do it?
Handlebars provides a data-variable, #index, for getting the index of current item in an #each iteration. However, like JavaScript arrays, #index is 0-based, so your result would be 0, 1, 2, ... - which is not what you asked for. To use #index, the impacted line in your template would become:
<th scope="row">{{#index}}</th>
If you require your serial numbers to start a 1 it will require a little more work. There is nothing out-of-the-box from Handlebars that will allow us to add 1 to #index. We would need to write a custom helper, a very simple one. For example:
helpers: {
increment(num) {
return num + 1;
}
}
And then our template would become:
<th scope="row">{{increment #index}}</th>
Here is an example fiddle for reference.
My feeling about this approach is that it is excessive to add a helper for such a simple purpose. I would recommend adding a SerialNumber property to each Product before it is passed to the template, before the res.render() call. It would look something like:
products.forEach((product, index) => {
products[index].SerialNumber = index + 1;
});
This way, the SerialNumber will be available to each Product in your template:
<th scope="row">{{this.SerialNumber}}</th>

send data from flask to html with 2 forms

I have flask sending data to html. Now, first time it does that its by render_template('page1.html', data=data) which populates the main table. Now when i click on any row of main table, i want to call flask again by url_for(entrypoint) and then again i will do render_template('page1.html', data=data2) for the 2nd table. But how to differentiate between them? i mean how will html know which data is coming for whom? please advice. I am novice in javascript and html. I am planning to keep the main table and secondary table under different forms. please advice if thats good decision or not.
Inside my html(page1.html), I have written
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script>
function getId(element) {
var row_index=element.rowIndex;
$.ajax({
url: '/get_details',
data: document.getElementById("table1").rows[row_index].cells[5].innerHTML),
type: 'POST',
success: function(response){
console.log(response);
},
error: function(error){
console.log(error);
}
});
This is the code in html for table1 and table2(table2 not done yet)
<section id="boxes" style="margin-top:-5%; margin-bottom:0%; position:absolute; z-index:1;">
<div class="box" style="margin-left:30px; margin-top:20px; z-index:1;">
<table id="table1">
<tr>
<th>NO</th>
<th> SUBJECT NAME</th>
<th>ASSIGNED TO</th>
<th>CREATED</th>
<th>DISEASES</th>
<th>SUBJECT ID</th>
<th>STATUS</th>
</tr>
{% for row in data %}
<tr onclick="getId(this)">
<td> {{ row[0] }}</td>
<td> {{ row[1] }}</td>
<td> {{ row[2] }}</td>
<td> {{ row[3] }}</td>
<td> {{ row[4] }}</td>
<td> {{ row[5] }}</td>
<td> {{ row[6] }}</td>
</tr>
{% endfor %}
</table>
</div>
<div class="box-two">
</div>
Inside my app.py
here is the flask code for the entry point:
#app.route('/get_details', methods=['POST'])
def get_details_user(patientid):
print(patientid)
This is the code for the entrypoint for the records which populates table1 as of now:
#app.route('/records')
#login_required
def records():
if current_user.priviledge:
data = get_records_by_userid(None)
else:
data = get_records_by_userid(current_user.id)
list_data = []
for row in data:
list_data.append([])
for col, val in row.items():
list_data[-1].append(val)
return render_template('records.html', data=list_data)
I don't see this in my flask code being triggered. Something wrong in my ajax code?? Also, how do I get the data from flask to this same html file for the second table?
Thanks a lot,
Sudip
Update: The error was coming due to ajax function syntax. Went with extra ')' in data in ajax...oops, thats bad
Add this to the JAvascript code:
$.ajax(function() {
headers = {'X-CSRFToken' : $('#csrf_token').val() },
...
});
This is the token the allows AJac to be validated

jQuery Datatables - Can't get input value from hidden pages

I have this table in my HTML:
<table>
<thead>
<tr>
<th>Id</th>
<th>Actual weight</th>
<th>New weight</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>10</td>
<td><input data-id="{{ object.id }}" type="number" name="input_new_weight" /></td>
</tr>
<tr>
<td>1</td>
<td>20</td>
<td><input data-id="{{ object.id }}" type="number" name="input_new_weight" /></td>
</tr>
<!-- multiply by 10 the number of trs -->
</tbody>
</table>
And I have this code in my javascript to get the input values:
var new_weights = []
$("input[name='input_new_weight']").each(function(index, element){
if( $(this).val() != "" ){
var object_new_weight ={
id: $(this).data('id'),
new_weight: $(this).val()
}
new_weights.push(object_new_weight);
}
});
console.log(new_weights);
I'm using jQuery DataTables plugin to generate the tables and have the possibili ty to filter, paginate, ordenate and etc.
In some tables I have more than 10 entries, so the paginations works here. In the example above, it will be 2 pages: 1 and 2.
When my javascript code is executed, it does only gets the inputs values from the visible table page. The inputs from the hidden pages are not get!
Let's suppose that in page 1 I put the new weight values as 35, 75 and 80 and in the page 2 I put 40, 54, 97. When my javascript code runs, it does just get the values from the visible page.
Please, can someone tell me why this is happening?
It's really straightforward you know datatable generates table on the fly so when you are on page 1, inputs corresponding to page 2 (40, 54, 97) aren't there at all on the page.
So I am guessing you have put your this code out in the global
$("input[name='input_new_weight']").each(function(index, element){
//stuff
});
This runs only one time; on initial loading of your page when inputs from only page 1 are there, what you rather need is to be able to run your code every-time datatable re-renders.There's a hook that you may use page.dt
Put this after the code where you initialize datatable
$('#yourtable').on('page.dt', function(){
$("input[name='input_new_weight']").each(function(index, element){
//stuff
});
});

Can I call a jquery or javascript function in grails g:each element?

I want to call a jquery function in grails g:each element, i'm using a function call on page load to filter a table which has a loop as follows
<g:each in="${sampleTypes}" status="i" var="sampleType">
<div class="uniq">${sampleType}</div>
<table id="sampleTable">
<thead>
<tr>
<th class="no-sort"><g:message code="labWorkItem.testUnit.label"
default="CustomerId" /></th>
<th class="no-sort"><g:message code="labWorkItem.testUnit.label"
default="OrderNo" /></th>
<th class="no-sort"><g:message code="labWorkItem.testUnit.label"
default="DateCreated" /></th>
<th class="no-sort"><g:message code="labWorkItem.testUnit.label"
default="Test unit" /></th>
<th class="no-sort no-visible"><g:message
code="labWorkItem.sampleType.label" default="Sample Type" /></th>
</tr>
</thead>
<tbody>
<g:each in="${labWorkItemInstance}" status="a" var="labWorkItem">
<tr class="${(a % 2) == 0 ? 'even' : 'odd'}">
<td>
${labWorkItem?.order?.customer?.customerId}
</td>
<td>
${labWorkItem?.order?.orderNo}
</td>
<td>
${labWorkItem?.order?.dateCreated}
</td>
<td >
${labWorkItem?.testUnit}
</td>
<td id = "labSample">
${labWorkItem?.testUnit?.sampleType}
</td>
</tr>
</g:each>
</tbody>
</table>
<g:textField name="singleValue" value="Blood" id="someHiddenField"/>
</g:each>
i am using the class "uniq" to filter the table
function typeSampleCollected() {
jQuery.fn.dataTableExt.afnFiltering.push(function(oSettings, aData,
iDataIndex) {
if (oSettings.nTable.id != "sampleTable") {
return true;
}
var uniq = jQuery("div.uniq").html();
alert(uniq);
jQuery("#someHiddenField").val(uniq);
var someHiddenField = jQuery("#someHiddenField").val()
if(someHiddenField){
//var sampleValue = jQuery("#someHiddenField").val();
//alert(sampleValue.toString());
if (someHiddenField != aData[4]){
console.log("sampleType"+someHiddenField);
console.log("aData"+aData[4]);
return false;
}
}
else{
console.log("else condition");
}
return true;
});
}
The problem is, it executes at the first on page load, only the first data of the loop executed others remains the same, i want the remaining data also to execute.
jQuery + HTML answer.
Your generated HTML will be wrong because the id "someHiddenField" will be duplicated. An id has to be unique within the HTML document. View the source of the document to check. Copy into an IDE or use w3c validator to check.
Once you have unique ID's you need to iterate over them and run your filter.
I am not sure whether by filter you are sending information back to the server. i.e. text blood results in only content relating to blood being displayed. I don't see any events in your code. Is the code incomplete?
A similar thing - click on an icon to only display items relating to that class. View code:
<g:each in="${assetTypes}" status="i" var="assetType">
<li>
<span class="atext">${assetType.name?.encodeAsHTML()}</span>
</li>
</g:each>
I used delegate() to late-bind jQuery to the click - use go() after 1.7 jQuery. The javascript had to be in a grails view because I use the gsp tags. With delegate() it could be anywhere:
/* Change asset types */
jQuery('body').delegate('[name=assetTypeSelector]', 'click', function() {
var newAssetIconId = jQuery(this).attr("id").split("-").pop();
// set the asset type.
${remoteFunction(controller: 'assetType', action: 'selector', name: 'assetTypeSelector', update: 'assetTypeSelector', params:'\'currentAssetTypeIconId=\' + newAssetIconId')}
});
Alternatively we have had a lot of success with DataTables which is a more complete solution.

Categories

Resources