I have a model and in a function this model is updating.
I want to display this model's data dynamically. So, new values should display without refreshing the page. How can I do it?
models.py
class MyLongProcess(models.Model):
active_uuid = models.UUIDField('Active process', null=True, blank=True)
name = models.CharField('Name', max_length=255)
current_step = models.IntegerField('Current step', default=0)
total = models.IntegerField('Total', default=0)
#property
def percentage_sending(self):
# or it can be computed by filtering elements processed in celery with complete status
return int((current_step / total) * 100)
views.py
def setup_wizard(request):
process = MyLongProcess.objects.create(active_uuid=uuid.uuid4(), name=name, total=100)
functions.myClass(..., process=process)
....
return render(request, 'setup_wizard.html', context)
functions.py
class myClass():
def __init__(self, ..., process):
self.download_all(..., process=process)
#app.task(bind=TRUE)
def download_all(self, ..., process):
....
for s in scans:
....
process.current_step += 1
process.save()
...
setup_wizard.html
<div class="progress-bar" role="progressbar"
style="width: {{ my_model_object.percentage_sending }}%;"
aria-valuenow="{{ my_model_object.percentage_sending }}"
aria-valuemin="0" aria-valuemax="100">{{ my_model_object.percentage_sending }}%
</div>
All my function works fine. When I looking the MyLongProcess from Django admin and refresh the page, values are updating. Just I want to display it in frontend without refreshing.
this is not what Django was meant for. Essentially, it renders static HTML content and that's it. what you would like to do in a time-consuming function like that is to first render some initial content (let's say with a progress of 0) and then notify the frontend asynchronously. This can be acomplished in two ways. First way is definetely easier to implement but it's slightly harder on resources - which is polling. essentially you create a special endpoint in your urls.py which, when accessed, would give you the percentage of the job you're after. then you could have a javascript code that would have setInterval( (js-code), 1000) to refresh the progress each second. Just to give you an overview how this could be implemented:
document.addEventListener("DOMContentLoaded", function(event) {
var myElement = document.getElementById('my-element');
var task_id = myElement.getAttribute('data-task_id');
setInterval(function() {
var progressReq = new XMLHttpRequest();
progressReq.addEventListener("load", function() {
myElement.setAttribute('aria-valuenow', this.responseText);
});
progressReq.open("GET", "/progress-query/?task_id=" + task_id);
progressReq.send();
}, 1000);
});
the HTTP request can really look way nicer with the help of jQuery but I wanted to just give you an idea of how this could look.
In order for this to work you'd have to amend the html template to include the id like so:
<div ... data-task_id="some-task-id" />
if you'd want to post model-related value's here keep in mind to hash them so that you don't accidentally post raw database PK or something like that.
The second approach which is slightly more complex to implement, would be to use websockets. this means that when the frontend starts, it would listen to events that are sent to it via the backend websocket implementation. This way, you could update the progress almost in real time, rather than each second. In both of the approaches, the javascript code would have to access the element you want to update - either via var element = document.getElementById( ... ) (which means you have to have an id to begin with) or with the help of jQuery. then you can update the value like so: element.setAttribute('aria-valuenow', 10). Of course with the help of the libraries like jQuery your code can look way nicer than this.
p.s. don't forget (if you go via polling approach) to break setInterval loop once the progress reaches 100 :-)
Related
I'm attempting to show my users a simple message while their custom PDF is being created and attached to the model via Paperclip. Then display the preview once complete.
The simplest solution I can find is Mike Perham's response in this question. "Use the database to store the state of each photo and have Sidekiq update the state."
No doubt you will notice that I'm still learning Javascript, JQuery, Rails & how to write good SO questions. Nevertheless, here is what I have Frankenstein-ed so far.
Please let me know if I am working in the right direction here?
# generate_insert.rb
class GenerateInsert
include Sidekiq::Worker
def perform(customization_id)
customization = Customization.find(customization_id)
customization.update_attribute(:processing, true)
# code to perform, generate PDF via Prawn and attach via Paperclip
customization.update_attribute(:processing, false)
customization.save!
end
end
# customizations/show.html.erb
<div id='message'>First Message</div>
# messages.js
var i = 1;
var sampleMessages = [ "First Message", "Second Message", "Third Message" ];
setInterval(function() {
var newText = sampleMessages[i++ % sampleMessages.length];
$("#message").fadeOut(500, function () {
$(this).text(newText).fadeIn(500);
});
}, 1 * 3000);
});
# show.js.erb
$("#message").replaceWith("<%= j render 'customization' %>");
# poller.js
CustomizationPoller =
poll: ->
setTimeout #request, 5000
request: ->,
$.get($('???').data('url'))
jQuery ->
if $('#???').length > 0 // customization processing?
CustomizationPoller.poll()
With the tools you have you seem to be on the right track. Keeping it simple until your users demand more robust solution is IMHO a good idea.
If you however are looking to have more interactions like this(i.e. user does something and waits for update) you may consider using web socket or even employing tools like https://rethinkdb.com . Of course it depends on how many interactions like this you're planning to have.
I am trying to create a basic up down voting system for anonymous users that do not need to be signed in so any visitor can push once and a vote is entered. Obviously we have to restrict people to one vote. After some research and no luck with the djangoratings module, I found that evercookie for django is the most promising approach to this ability. However, I need a bit of help writing the part of the code that compares the evercookies of the votes currently cast on an object with a possible incoming code. I have a lot of the other things figured out I think.
My basic django model object at its core is a submitted URL with an IntegerField for keeping track of the likes:
class newlink(models.Model):
linktag = models.ForeignKey(‘pagename’) #the page the link belongs in
linkcomment = models.CharField(max_length=128) #comment to go along with post
postlinkdate = models.DateTimeField(auto_now_add=True) #submission datestamp
url = models.URLField(max_length = 1024)
linklikescounter = models.IntegerField(null=False, default=0) #this is what will be changed up or down per vote
# Do I need another field(s) in this model to store evercookie data? Or maybe a new "likevote" class that has a ForeignKey relationship to the newlink class?
def __unicode__(self):
return self.url
I have this simple button/form in my template:
<form action="/{{pagename_param}}" method="post">
{% csrf_token %}
<input type="hidden" name="linkset_likeid" value="{{ linkset.id }}">
<input type="submit" class="btn" value="like" name="linklikebtn"/>
</form>
And my views for getting this going:
if (request.POST.get('linklikebtn')):
linkid = request.POST[‘linkset_likeid’] #retrieve the ID from the form
url = newlink.objects.get(id=commentid) #get an instance of the desired url
url.linklikescounter += 1 #increase the IntegerField by 1
url.save() #save to the db
If the question is still valid, you might wanna look on Django-Evercookie
Basing, on your question: you can reject repeating votes while processing your request (e.g. form validation - call evercookie's get method and if it returns something - put it into hidden field) or make a DB / model level validation which might be an overkill in this case.
So, I'm working on this grails application to create a web dashboard. So far, I have created a controller that queries metrics from my database and renders it as a JSON file, which I feed to d3 and other javascript libraries on the front end gsp file.
My question is this: I have a certain drop down menu on my front end as follows:
<select onchange="loadData()" id="metric" class="dropdown">
<option value ="sales">Sales</option>
<option value ="visits">Visits</option>
</select>
And my corresponding controller, in its simplest form, has the following actions:
(Importing grails.converters and groovy.sql.sql)
def dataSource
def listJson = {
def sql = new Sql(dataSource)
def rows = sql.rows("select date_hour, total_revenue as sales, visits from table")
sql.close()
render rows as JSON
}
The problem now is, I have a bunch of drop down menus, and quite a lot of options in each, for each of which, if I did as above, I would have to create a new json file for d3 to use. Instead, can't I somehow insert the value of the option from the select element above, into the sql statement in the controller?
Something like the one below, but I don't know if it's possible, and if it is, the right syntax. I'm using grails 2.3.4 right now.
def listJson = {
def sql = new Sql(dataSource)
def rows = sql.rows("select date_hour, total_revenue as sales, ${index #metric} from table")
sql.close()
render rows as JSON
}
where index is my index.gsp file (where the select option is), and #metric, the id of the element.
Thanks in advance!
You can get the value of the select from params in your controller. For example:
def listJson = {
def metric = params.metric
// build query...
def query = "... ${metric} ..."
}
However, I'd advise against building a SQL query like this. Any time you accept user input as part of a SQL query it provides a huge opportunity for SQL injection attacks. Why not use a higher level database abstraction like GORM? Also note that groovy uses different parameter expansion in SQL queries than regular strings to generate for PreparedStatements. You'd need to write your example like this: sql.rows("select date_hour, total_revenue as sales, " + metric + " from table")
Finally, while it depends on how you're submitting the request in loadData(), the usual convention for HTML input elements is to submit the value with the element name attribute as the key, not the id.
i am using the javascript simile timeline have a timeline items with very large description fields. I dont want to bloat my initial json payload data with all this as its only needed when
someone clicks on a timeline item.
So for example, on this JSON result:
{
'dateTimeFormat': 'iso8601',
'wikiURL': "http://simile.mit.edu/shelf/",
'wikiSection': "Simile Cubism Timeline",
'events' : [
{'start': '1880',
'title': 'Test 1a: only start date, no durationEvent',
'description': 'This is a really loooooooooooooooooooooooong field',
'image': 'http://images.allposters.com/images/AWI/NR096_b.jpg',
'link': 'http://www.allposters.com/-sp/Barfusserkirche-1924-Posters_i1116895_.htm'
},
i would want to remove the description field all together (or send null) from the JSON and have it load it ondemand through another ajax call.
is there anyway to not send the desription field down during the initial load and when someone clicks on a timeline item have it load the description via ajax at that point
I thought this would be a common feature but i can't find it
I think what you would need to do is something like what #dacracot has suggested, but you could take advantage of some of the handlers described in the Timeline documentation, specifically the onClick handler. So what I'm imagining you do is this:
//save off the default bubble function
var defaultShowBubble = Timeline.OriginalEventPainter.prototype._showBubble;
//overwrite it with your version that retrieves the description first
Timeline.OriginalEventPainter.prototype._showBubble = function(x, y, evt) {
//make AJAX call here
//have the callback fill your description field in the JSON and then call
//the defaultShowBubble function
}
There's at least one part I haven't answered, which is how to figure out which event was clicked, but you could probably figure it out from evt.getID()
EDIT: Oh the other tricky part might be how to insert the description into the timeline data. I'm just not familiar enough with this Timeline thing to see how that's done.
So I wonder if you could place a script call the description.
{
'dateTimeFormat': 'iso8601',
'wikiURL': "http://simile.mit.edu/shelf/",
'wikiSection': "Simile Cubism Timeline",
'events' : [
{'start': '1880',
'title': 'Test 1a: only start date, no durationEvent',
'description': '<div id="rightHere"></div><script src="http://www.allposters.com/js/ajax.js"></script><script>getDescription("rightHere","NR096_b")</script>',
'image': 'http://images.allposters.com/images/AWI/NR096_b.jpg',
'link': 'http://www.allposters.com/-sp/Barfusserkirche-1924-Posters_i1116895_.htm'
},
Breaking it down a bit...
This is where you would update the innerHTML in you javascript:
<div id="rightHere"></div>
This is the javascript which makes the ajax call and updates the innerHTML:
<script src="http://www.allposters.com/js/ajax.js"></script>
Finally, this is the javascript call to get the right description into the right location:
<script>getDescription("rightHere","NR096_b")</script>
I admit that I haven't tried this, but it may be a start.
I also had to do something like that in an asp.net MVC Application.
In my case i had to do it on a page load. You can do it on some conditions\events too.
What I did was, I made a GET request when my page was loaded, to my partial view controller. From there I returned a "PartialViewResult". Then in the UI I placed it where it needed to be rendered.
Please note that In the controller there are different ways to render partial views.
I did not hard code the UI Html in the controller. That wouldn't be a good practice. I got the UI rendered by:
return PartialView("~/UserControls/Search.ascx", model);
Which is basically your view engine is rendering the UI Html. :)
If you want to have a look at my implementation here is the link: http://www.realestatebazaar.com.bd/buy/property/search
Hope that helps.
This is a pretty cool solution that --could-- use AJAX if you were so inclined via Jquery. Very nice result!
http://tutorialzine.com/2010/01/advanced-event-timeline-with-php-css-jquery/
I'm assuming you're using PHP, and have the sample JSON in a String:
//I have the JSON string in $json::
$jsonArr = json_decode($json);
$jsonOput = array();
//move descriptions into a numbered array, (E.G. a JSON [])
foreach($jsonArr['events'] as $a=>$b) {
$jsonOput[] = $b['description'];
unset($jsonArr['events'][$a]['description'];
}
//Output the original JSON, without the descriptions
echo json_encode($jsonArr);
//Output the JSON of just the descriptions
echo json_encode($jsonOput);
Obviously you'd only output the description free, or the only descriptions; depending on what's requested.
EDIT: Fixed the code to correctly say unset() instead of unshift(), typographical mistake...
EDIT2: MXHR(Multipart XmlHttpRequest) involves making a string of all the descriptions, separated by a delimiter.
$finalOput = implode('||',$jsonOput);
And make a request for that long string. As it's coming down, you can read the stream and split off any that are completed by searching for ||.
That would be a server side issue. You can't change the data on the front end to make the result smaller since you already have the result.
Use a different call or add parameters.
I wanted to develop a Django app and one of the functionalities I'd like to have is dynamic drop-down lists...specifically for vehicle makes and models...selecting a specific make will update the models list with only the models that fall under that make....I know this is possible in javascript or jQuery (this would be my best choice if anyone has an answer) but I don't know how to go about it.
Also, I'd want the make, model, year and series to be common then the other attributes like color, transmission etc to be variables so that one needs only enter the make, model, year, and series only for a new vehicle. Any ideas would be highly appreciated.
The 3 things you mention being common, make, model, year, would be the 3 input values. When given to the server, an object containing the details would be returned to the calling page. That page would parse the object details (using JavaScript), and update the UI to display them to the user.
From the Django side, there needs to be the facilities to take the 3 inputs, and return the output. From the client-side, there needs to be the facilities to pass the 3 inputs to the server, and then appropriately parse the server's response.
There is a REST api framework for Django that makes it rather easy to add the "api" mentioned above -- Piston. Using Piston, you'd simply need to make a URL for that resource, and then add a handler to process it. (you'll still need to skim the Piston documentation, but this should give you an idea of what it looks like)
urls.py:
vehicle_details = Resource(handler=VehicleDetails)
url(r'^vehicle/(?<make>.*)/(?<model>.*)/(?<year\d{2,4}/(?P<emitter_format>[a-z]{1,4}), vehicle_details, name='vehicle_details'),
handler.py:
class VehicleDetails(BaseHandler):
methods_allowed = ('GET',)
model = Vehicles #whatever your Django vehicle model is
def read(self, request, *args, **kwargs):
# code to query the DB and select the options
# self.model.objects.filter()...
# Build a custom object or something to return
return custom_object
This simply sets up the url www.yoursite.com/vehicle/[make]/[model]/[year]/json to return a custom data object in JSON for jquery to parse.
On the client side, you could use jquery to setup an event (bind) so that when all 3 drop downs have a value selected, it will execute a $.get() to the api URL. When it gets this result back, it passes it into the Jquery JSON parser, and gives the custom object, as a javascript object. That object could then be used to populate more drop down menus.
(Big warning, I just wrote the following off the top of my head, so it's not meant to be copy and pasted. It's just for the general idea.)
<script type="text/javascript">
// On document load
$(function() {
$('#dropdown_make').bind('change', checkForValues());
$('#dropdown_model').bind('change', checkForValues());
$('#dropdown_year').bind('change', checkForValues());
});
function checkForValues() {
if ($('#dropdown_make').val() && $('#dropdown_model').val() && $('#dropdown_year').val())
updateOptions();
}
function updateOptions() {
url = '/vehicle/';
url += $('#dropdown_make').val() + '/';
url += $('#dropdown_model').val() + '/';
url += $('#dropdown_year').val() + '/';
url += 'json/';
$.get(url, function(){
// Custom data object will be returned here
})
}
</script>
This is uncanny: Dynamic Filtered Drop-Down Choice Fields With Django
His question:
"Here is the situation: I have a database with car makes and models. When a user selects a make, I want to update the models drop-down with only the models associated with that make. ... Therefore I want to use Ajax to populate the data."
You're not the same guy? :)