5👍
After trying the two different approaches suggested by Brandon and Murat, Brandon’s suggestion proved the most successful.
-
Create a wrapper template that includes the javascript from http://djangosnippets.org/snippets/679/. The javascript has been modified: (i) to work without a form (ii) to hide the progress bar / display results when a ‘done’ flag is returned (iii) with the JSON update url pointing to the view described below
-
Move the slow loading function to a thread. This thread will be passed a cache key and will be responsible for updating the cache with progress status and then its results. The thread renders the original template as a string and saves it to the cache.
-
Create a view based on upload_progress from http://djangosnippets.org/snippets/678/ modified to (i) instead render the original wrapper template if progress_id=” (ii) generate the cache_key, check if a cache already exists and if not start a new thread (iii) monitor the progress of the thread and when done, pass the results to the wrapper template
-
The wrapper template displays the results via
document.getElementById('main').innerHTML=data.result
(* looking at whether step 4 might be better implemented via a redirect as the rendered template contains javascript that is not currently run by document.getElementById('main').innerHTML=data.result
)
5👍
Another thing you could do is add a javascript function that displays a loading image before it actually calls the Django View.
function showLoaderOnClick(url) {
showLoader();
window.location=url;
}
function showLoader(){
$('body').append('<div style="" id="loadingDiv"><div class="loader">Loading...</div></div>');
}
And then in your template you can do:
<a href='#' onclick="showLoaderOnClick('{% url 'my_namespace:my_view' %}')">This will take some time...</a>
Here’s a quick default loadingDiv : https://stackoverflow.com/a/41730965/13476073
Note that this requires jQuery.
- Registering Django system checks in AppConfig's ready() method
- Django REST Framework: Validate before a delete
- Django admin – select reverse foreign key relationships (not create, I want to add available)
2👍
a more straightforward approach is to generate a wait page with your gif etc. and then use the javascript
window.location.href = 'insert results view here';
to switch to the results view which starts your lengthy calculation. The page wont change until the calculation is finished. When it finishes, then the results page will be rendered.
- Why does Django South 1.0 use iteritems()?
- Django is very slow on my machine
- How can I test if my redis cache is working?
- Django: Distinct foreign keys
- Django models across multiple projects/microservices. How to?
1👍
Here’s an oldie, but might get you going in the right direction: http://djangosnippets.org/snippets/679/
1👍
A workaround that I chose was to use beforunload
and unload
events to show the loading image. This can be used with or without window.load
. In my case, it’s the view that is taking a great amount of time and not the page loading, hence I am not using window.load
(because it’s already a lot of time by the time window.load
comes into picture, and at that point of time, I do not need the loading icon to be shown anymore).
The downside is that there is a false message that goes out to the user that the page is loading even when when the request has not even reached the server or it’s taking much time. Also, it doesn’t work for requests coming from outside my website. But I’m living with this for now.
Update: Sorry for not adding code snippet earlier, thanks @blockhead. The following is a quick and dirty mix of normal JS and JQuery that I have in the master template.
Update 2: I later moved to making my view(s) lightweight which send the crucial part of the page quickly, and then using ajax to get the remaining content while showing the loading icon. It needed quite some work, but the end result is worth it.
window.onload=function(){
$("#load-icon").hide(); // I needed the loading icon to hide once the page loads
}
var onBeforeUnLoadEvent = false;
window.onunload = window.onbeforeunload= function(){
if(!onBeforeUnLoadEvent){ // for avoiding dual calls in browsers that support both events
onBeforeUnLoadEvent = true;
$("#load-icon").show();
setTimeout(function(){
$("#load-icon").hide();},5000); // hiding the loading icon in any case after
// 5 seconds (remove if you do not want it)
}
};
P.S. I cannot comment yet hence posted this as an answer.
- 'admin' is not a registered namespace in Django 1.4
- Django forms give: Select a valid choice. That choice is not one of the available choices
- Why is django's settings object a LazyObject?
0👍
Iterating HttpResponse
https://stackoverflow.com/a/1371061/198062
Edit:
I found an example to sending big files with django: http://djangosnippets.org/snippets/365/ Then I look at FileWrapper class(django.core.servers.basehttp):
class FileWrapper(object):
"""Wrapper to convert file-like objects to iterables"""
def __init__(self, filelike, blksize=8192):
self.filelike = filelike
self.blksize = blksize
if hasattr(filelike,'close'):
self.close = filelike.close
def __getitem__(self,key):
data = self.filelike.read(self.blksize)
if data:
return data
raise IndexError
def __iter__(self):
return self
def next(self):
data = self.filelike.read(self.blksize)
if data:
return data
raise StopIteration
I think we can make a iterable class like this
class FlushContent(object):
def __init__(self):
# some initialization code
def __getitem__(self,key):
# send a part of html
def __iter__(self):
return self
def next(self):
# do some work
# return some html code
if finished:
raise StopIteration
then in views.py
def long_work(request):
flushcontent = FlushContent()
return HttpResponse(flushcontent)
Edit:
Example code, still not working:
class FlushContent(object):
def __init__(self):
self.stop_index=2
self.index=0
def __getitem__(self,key):
pass
def __iter__(self):
return self
def next(self):
if self.index==0:
html="loading"
elif self.index==1:
import time
time.sleep(5)
html="finished loading"
self.index+=1
if self.index>self.stop_index:
raise StopIteration
return html
- Installing django 1.5(development version) in virtualenv
- Django ForeignKey limit_choices_to a different ForeignKey id
- How do I use perform_create to set a field automatically in Django Rest Framework?
0👍
Here is another explanation on how to get a loading message for long loading Django views
Views that do a lot of processing (e.g. complex queries with many objects, accessing 3rd party APIs) can take quite some time before the page is loaded and shown to the user in the browser. What happens is that all that processing is done on the server and Django is not able to serve the page before it is completed.
The only way to show a show a loading message (e.g. a spinner gif) during the processing is to break up the current view into two views:
-
First view renders the page with no processing and with the loading message
-
The page includes a AJAX call to the 2nd view that does the actual processing. The result of the processing is displayed on the page once its done with AJAX / JavaScript
- How to filter filter_horizontal in Django admin?
- Django reverse error: NoReverseMatch
- Installing django 1.5(development version) in virtualenv