How can I update the photo each second in my django template? - django

everyone. I am pretty new with django.
There is a particular position to show the photo in my django template, and the photo should be updated each second. How can I do that? (Paths for new photos come from the database. I know how to get them from db.)
I only know how to return a html with a url request, but how can I update a particular item in that html without a new url request?
More info.: The photos have to be shown are generated in real time by another process, so do the paths for the photos.
Actually, I do not implement it yet. I am still learning django, but I can simulate the situation by simple codes as follows:
urls.py:
urlpatterns = [ url(r'^hello/$', hello_world),]
views.py:
from django.shortcuts import render
from datetime import datetime
def hello_world(request):
return render(request, 'hello_world.html', {
'current_time': str(datetime.now()),
})
hello_world.html:
<!-- hello_world.html -->
<!DOCTYPE html>
<html>
<head>
<title>I come from template!!</title>
<style>
body {
background-color: lightyellow;
}
em {
color: LightSeaGreen;
}
</style>
</head>
<body>
<script>
setInterval(function() {
fetch("{% url 'hello_ajax' %}").then(function (response) {
var current_time = response.json().current_time;
console.log(current_time);
document.getElementById("test").innerHTML = current_time;
});
}, 1000);
</script>
<h1>Hello World!</h1>
<em id="test"></em>
</body>
</html>
We can update the current_time by refresh the page, but how about update the current_time each second without refresh the page? We can see the photo as the current_time to simulate my case.
Update:
It finally works:
<script>
setInterval(function() {
fetch("{% url 'hello_ajax' %}").then(response => response.json())
.then(data => {
// you can access your data here
document.getElementById("test").innerHTML = data.current_time;
});
}, 1000);
</script>
I am wondering why it is not working with:
<script>
setInterval(function() {
fetch("{% url 'hello_ajax' %}").then(response =>{
// you can access your data here
document.getElementById("test").innerHTML = response.json().current_time;
});
}, 1000);
</script>
it says that "(index):22 Uncaught (in promise) TypeError: Failed to execute 'json' on 'Response': body stream is locked at fetch.then.data"
Any idea?

Unfortunately, you can achieve it only with some JavaScript, and thing like setTimeout. If it won't be a big list, you could render it to the JavaScript array and then use e.g. setTimeout to switch the photo. It's not the best idea (I even remember reading some article with some valid points why it is a bad, will try to find it), but would do the work.
So, you could do something like this, at the end of body in the template:
<script>
arrayOfUrls = [
{% for url in urls}"{{ url }}",{% endfor %}
];
function switchPhoto(urlArray, switchTo) {
// if to go back to 0 if array finished
document.getElementById("your-photo-id").src = urlArray[switchTo];
setTimeout(switchPhoto, 1000, urlArray, switchTo + 1);
}
switchPhoto(arrayOfUrls, 0);
</script>
After update:
if you don't want to refresh the page, the solution would be probably the following:
views.py
from django.http import JsonResponse
def hello_world(request):
return render(request, 'hello_world.html', {
'current_time': str(datetime.now()),
})
def hellow_world_ajax(request):
return JsonResponse({'current_time': str(datetime.now())})
Add url(r'^hello_ajax/$', hellow_world_ajax, name="hello_ajax"), to urls.py.
And in the body of the template write JavaScript using e.g.: setInterval and either vanilla JS fetch or some js library / framework insert the periodic update logic:
<script>
setInterval(function() {
fetch("{% url 'hello_ajax' %}").then(function (response) {
document.getElementById("your-photo-id").src = response.json().current_time;
});
}, 1000);
</script>

Related

How to add information in a page without refreshing the page?

I would like to have a page in my django application that has a button that search a product and after selecting quantities gets added to the page (without reloading) in a list where the total get calculated (something like that), I am a beginner in programing and I have a week reading and investigated how to do it but I don't found anything.
Is because you need other programming language? Or could you indicate me some documentation or some example that I can read. Mostly because for my inexperience I don't know how to identify the relevant information in the documentation or even what to look for.
This can be done using Ajax call,
check this example:
forms.py
class sampleForm(forms.Form):
input = forms.CharField()
views.py
from django.http import JsonResponse
def sampleview(request):
input = request.POST.get('input', None)
#perform your logic here
#let us say your data is in variable result
result = {'product1' : 'python' ,'product2' : 'django' , 'product3' : 'ajax' }
return JsonResponse(result)
urls.py
from django.urls import path, include
from . import views
urlpatterns = [
path('sampleview',views.sampleview,name='sampleview'),
]
your HTML
<form method="POST">
{% csrf_token %}
{{form.as_p}}
<button id="sampleform-submit" type="submit">submit</button>
</form>
<div id="results"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script>
$("#sampleform-submt").click(function(){
e.preventDefault();
var form = $('#id_input').closest("form")
//id_input is id of input tag generated by form and above line selects the form
$.ajax({
url : "{% url 'sampleview' %}",
type: "POST",
data : form.serialize(),
dataType: 'json',
success: function(data){
#data is 'result' you return in sampleview function
$("#results").append('<p> '+ data.product1 +'</p>');
$("#results").append('<p> '+ data.product2 +'</p>');
$("#results").append('<p> '+ data.product3 +'</p>');
}
});
}
</script>
I hope this helps

Django - How can I pass information from my google map to my view?

I am using Django and I have my map set up like this in my index.html:
<div id="map"></div>
<script>
var map;
function initMap(){
map = new google.maps.Map(document.getElementById('map'),{
center: {lat: {{clat}}, lng: {{clng}}},
zoom:12
});
}
</script>
<script src={{gmap_url}} async def></script>
First I want to initiate the map with markers from my database which fit within the shown area. Then add the ability for the user to change the shown area (drag or zoom) and press a button which will query my database based on the newly shown area of the map. How can I tell what area my map is currently showing?
I'd also like to query my database when the user clicks on a marker using information stored in that marker, how can I pass information to my view onclick?
You can get the bounding box from the map and then send that data as a query parameter in a GET request to your django server, which can then perform a spatial query on your data in that bounding box and send data back to your map. It would look something like this.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<script src={{gmap_url}}></script>
<script src={{axios_url}}></script>
<script src={{js-cookie_url}}></script>
</head>
<button onclick="sendBounds()">Click me to send bounds!</button>
<div id="map"></div>
</html>
<script>
var map
const postRequest = axios.create({
baseURL: '/api',
timeout: 5000,
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': Cookies.get('csrftoken')
}
})
function initMap() {
map = new google.maps.Map(document.getElementById('map'),{
center: {lat: {{clat}}, lng: {{clng}}},
zoom:12
})
}
function sendBounds() {
const payload = { 'bounds': map.getBounds() }
postRequest.get(`models/`, { params: payload })
.then(response => response.data.results)
}
</script>
views.py
from django.contrib.gis.geos import Polygon
from rest_framework import generics
from .models import Model
from .serializers import ModelSerializer
class ModelAPIView(generics.ListAPIView):
lookup_field = 'pk'
serializer_class = ModelSerializer
def get_queryset(self):
bounds = self.request.GET.get('bounds')
# Probably need to cast all these string coordinates to floats here
geom = Polygon.from_bbox(bounds)
queryset = Model.objects.filter(poly__contained=geom)
return queryset
def get_serializer_context(self, *args, **kwargs):
return {'request': self.request}
urls.py
from django.urls import path
from .views import ModelAPIView
urlpatterns = [
path('api/models/', ModelAPIView.as_view(), name='model-list'),
]

Passing variables from template to view

Ok, I'm working on a website and I need a way to save score to database. I get the score from an iFrame, but I dont know how to pass it to a Django view to save it to the DB.
This is the template I'm using to get the score:
{% block content %}
<script>
/* global $ */
$(document).ready(function() {
'use strict';
$(window).on('message', function(evt) {
//Note that messages from all origins are accepted
//Get data from sent message
var msg = evt.originalEvent.data;
if(msg.messageType == "SCORE")
{
msg.score
???
}
});
});
</script>
<iframe id="game_iframe" src={{gameurl}}></iframe>
{% endblock %}
I will be using some sort of model to save the score eventually but now I'm just interested passing this variable from the template to the view.
What you need to do is setup an Ajax request & handle the score etc in a django view.
Take a read of this & it should give you everything you need; http://www.tangowithdjango.com/book/chapters/ajax.html
You'll probably end up with JS a bit like this;
{% block content %}
<script>
/* global $ */
$(document).ready(function() {
'use strict';
$(window).on('message', function(evt) {
//Note that messages from all origins are accepted
//Get data from sent message
var msg = evt.originalEvent.data;
if(msg.messageType == "SCORE")
{
$.get('/game/save_score/', {score: msg.score}, function(data){
$('#score').html(data);
});
}
});
});
</script>
<iframe id="game_iframe" src={{gameurl}}></iframe>
{% endblock %}
And a view;
def save_score(request):
context = RequestContext(request)
score = None
if request.method == 'GET':
score = request.GET['score']
# Do whatever you need to save the score.
return HttpResponse(score)

Django-printing of random values

I want that the random number generated should be printed on the webpage, ie via HttpResponse(x) after every 5 seconds, for which I have used the time.sleep function.
How do I print the randomly generated values without refreshing the page?
Here is my view.py file
def main(request):
return render(request,'graphs/index.html')
def random_generator(request):
return HttpResponse(randrange(0, 5))
Urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('',
url(r'random/','apps.graph.views.main', name = 'graph_home'),
url(r'random_gen/','apps.graph.views.random_generator', name = 'random'),
)
Template
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function refreshRandom() {
$.ajax({
url: 'random/',
dataType: 'html',
success: function(data) {
$('#random').html(data);
},
complete: function() {
window.setTimeout(refreshRandom, 5000);
}
});
}
window.setTimeout(refreshRandom, 5000);
</script>
</head>
<body>
<div id='random'></div>
</body>
</html>
You create a view for the main page, and another view that returns a random number. Then you write an ajax call in javascript to refresh what you see. Like this:
views.py
def main(request):
return render(request, 'index.html')
def random_generator(request):
return HttpResponse(randrange(0, 5))
urls.py
url('^main/$', 'myapp.views.main'),
url('^random/$', 'myapp.views.random_generator')
Then in your template:
<script type="text/javascript">
function refreshRandom() {
$.ajax({
url: '/random/',
dataType: 'html',
success: function(data) {
$('#random').html(data);
},
complete: function() {
window.setTimeout(refreshRandom, 5000);
}
});
}
window.setTimeout(refreshRandom, 5000);
</script>
<div id='random'></div>
Though I don't really see what would you gain by doing this through a django view. If that's all you want to do, you might want to try and write the whole thing on the client side with javascript.
You can use pure JS to achieve it, no need to bother Django:
var random_interval = setInterval(function() {
var random_number = 1 + Math.floor(Math.random() * 6);
$('#random-number').text(random_number);
}, 5000); // every 5 second

jquery ajax / django - present form in a bootstrap modal and re-show if validation was not successful

my use case is:
a) Present a form loaded via ajax in a bootstrap modal, the fancy overlay effect stuff.. . I followed these instructions.
This works fine. (see code below)
b) Submit this form back to my Django app, try to validate it, and if it does not validate, re-show the form with the errors in the fancy bootstrap modal.
I can reload the form via ajax, but I m not able to represent it again in the modal.
Note: I did not include the view since it does nothing special. Only instantiating and validating the form.
Quite a lot to read below, so just continue if you think the use case sounds interesting...
My taskList.html looks like this:
<table id="listItemTable" class="table table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Edit</th>
</tr>
</thead>
<tbody>
<tr>
<td>Task 1</td>
<td><a class="editItem" href="/update/item/1/">edit</a></td>
</tr>
</tbody>
</table>
<div class="modal hide" id="itemFormModal"></div>
<div id="modalExtraJsPlaceholder"></div>
.js for loading the form + showing the bootstrap modal + binding form to a .jquery submit call:
$(document).ready(function() {
modalConnect();
});
<script type="text/javascript">
//connects the modal load for each <a> with class editItem
//Functionality 1
//loads an item edit form from the server and replaces the itemFormModal with the form
//presents the modal with $("#itemFormModal").modal('show');
//Functionality 2
//loads some extra js "modalExtraJsHtml"
//calls the function "submitItemModalFormBind" which has been loaded via "modalExtraJsHtml"
function modalConnect(){
$(".editItem").click(function(ev) { // for each edit item <a>
ev.preventDefault(); // prevent navigation
url = ($(this)[0].href); //get the href from <a>
$.get(url, function(results){
var itemForm = $("#ajax_form_modal_result", results);
var modalExtraJs = $("#modalExtraJs", results);
//get the html content
var modalExtraJsHtml = modalExtraJs.html();
//update the dom with the received results
$('#itemFormModal').html(itemForm);
$('#modalExtraJsPlaceholder').html(modalExtraJsHtml);
$("#itemFormModal").modal('show');
submitItemModalFormBind(); //bind loaded form to ajax call
}, "html");
return false; // prevent the click propagation
})
}
</script>
The itemForm returned from the view looks like this:
<form id="#ajax_form_modal_result" class="well" method="post" action="/update/item/{{ item.id }}">
<div id="ajax_form_modal_result_div">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h3>Edit Item</h3>
</div>
<div class="modal-body">
{% csrf_token %}
{{form.as_p}}
</div>
<div class="modal-footer">
<input class="btn btn-primary" type="submit" value="Save" />
<input name="cancel" class="btn" type="submit" value="Cancel"/>
</div>
</div>
</form>
Loading and showing the modal works fine.
But now comes the second part which does not work as expected. The issue is the following. If the form does not validates, the view returns the form. The returned form should be shown again in the bootstrap modal. But the result is that ONLY the form is presented in the browser, everything else is lost. No css, no table, only the form. Quite ugly.. Thus I did not achieve to update the ajax_form_modal_result_div. Can anyone help me out here what I m doing wrong..!?
The view returns also the js function 'submitItemModalFormBind' which prevents the form default behavior and sends the form via ajax.
<div id="modalExtraJs">
//ajax bind for update item form visualized via modal
function submitItemModalFormBind(){
var url = "{% url updateItem item.pk %}";
$('#ajax_form_modal_result').submit(function(){
$.ajax({
type: "POST",
url: "{% url updateTask item.pk %}",
data: $(this).serialize(),
success:function(response){
var div = $("ajax_form_modal_result_div", response);
$('#ajax_form_modal_result_div').html(div);
},
error: function (request, status, error) {
console.log("failure");
console.log(request.responseText);
}
});
});
return false;
}
</div>
Found a working approach (based upon this solution - and enhanced it with handling of invalid forms) and will post it for anybody who also want to use the stunning beautiful bootstrap modals with django. Major issue with the code above was that I did not correctly disabled the default behavior of the submit button and the approach for loading additional js was not a good idea. So I changed my strategy.
On documentReady or ajaxStop event bind the click event of the hyperlinks to the modalConnect function. Note that you only need the ajaxStop function if you have some kind of ajax which updates the content of your table (which I have):
<script type="text/javascript">
$(document).ready(function() {
modalConnect();
});
</script>
<script type="text/javascript">
$( document ).ajaxStop( function() {
modalConnect();
});
</script>
The modalConnect function which loads the form which we want to present in the modal and a formUpdateURLDiv:
<script type="text/javascript">
function modalConnect()
{
//unbind the click event. If not done we will end up with multiple click event bindings, since binding is done after each ajax call.
$(".editItem").unbind('click');
//bind the click event
$(".editItem").click(function(ev) { // for each edit item <a>
ev.preventDefault(); // prevent navigation
var url = this.href; //get the href from the <a> element
$.get(url, function(results){
//get the form
var itemForm = $("#ajax_form_modal_result", results);
//get the update URL
var formUpdateURLDiv = $("#formUpdateURL", results);
//get the inner html of the div
var formUpdateURL = formUpdateURLDiv.html();
//update the dom with the received form
$('#itemFormModal').html(itemForm);
//show the bootstrap modal
$("#itemFormModal").modal('show');
$(document).ready(function () {
//bind the form to an ajax call. ajax call will be set to the received update url
submitItemModalFormBind(formUpdateURL);
});
}, "html");
return false; // prevent the click propagation
})
}
</script>
the formUpdateURL includes a server generated (see included view below) url to which the loaded form has to make its form submission call. We use this url to "init" the submitItemModalFormBind function:
<script type="text/javascript">
function submitItemModalFormBind(url){
//bind the form. prevent default behavior and submit form via ajax instead
$('#ajax_form_modal_result').submit(function(ev){
$.ajax({
type: "POST",
url: url,
data: $(this).serialize(),
success:function(response, textStatus, jqXHR){
var form = $("#ajax_form_modal_result_div", response);
//form is returned if it is not valid. update modal with returned form
//change this "if" to check for a specific return code which should be set in the view
if (form.html()) {
console.log('Form was invalid and was returned');
//update modal div
$('#ajax_form_modal_result_div').html(form);
$("#itemFormModal").modal('show');
}
//form is not returned if form submission succeeded
else{
//update the entire document with the response received since we received a entire success page and we want to reload the entire page
document.open();
document.write(response);
document.close();
//sort by modified date descending
//var notificationDiv = $("#notification", response);
//$('#notification').html(notificationDiv.html());
console.log('Form was valid and was not returned');
$("#itemFormModal").modal('hide');
}
},
error: function (request, status, error) {
var div = $("ajax_form_modal_result_div", request.responseText);
$('#ajax_form_modal_result_div').html(div);
//implement proper error handling
console.log("failure");
console.log(request.responseText);
}
});
return false;
});
}
</script>
..and to see what is going on at the server see below the view which handles the logic:
class UpdateTaskModalView(LoginRequiredMixin, View):
template = 'list_management/crud/item/update_via_modal.html'
def get_logic(self, request, task_id, **kwargs):
task = get_object_or_404(Task.objects, pk=task_id)
task_form = TaskForm(instance=task)
context = {
'model_form': task_form,
'item': task,
}
return context
def post_logic(self, request, task_id, **kwargs):
task = get_object_or_404(Task.objects, pk=task_id)
task_form = TaskForm(request.POST, instance=task)
if task_form.is_valid():
task = task_form.save(commit=False)
task.modified_by = request.user
task.save()
messages.add_message(request, messages.INFO, 'Item "%s" successfully updated' % (task.name))
return ('redirect', HttpResponseRedirect(reverse('show_list_after_item_update', kwargs={'list_id':task.list.pk, 'item_id':task.pk})))
context = {
'model_form' : task_form,
'list': task.list,
'item': task,
}
return ('context', context)
def get(self, request, task_id, **kwargs):
context = self.get_logic(request, task_id, **kwargs)
return render_to_response(
self.template,
context,
context_instance = RequestContext(request),
)
def post(self, request, task_id, **kwargs):
post_logic_return = self.post_logic(request, task_id, **kwargs)
if post_logic_return[0] == 'redirect':
return post_logic_return[1]
if post_logic_return[0] == 'context':
context = post_logic_return[1]
return render_to_response(
self.template,
context,
context_instance = RequestContext(request),
)
..the form template is already included in my question: ajax_form_modal_result_div, you only have to provide also the formUpdateURL. I did it via the template, which seems quite odd now that I write this post. could be easily provided via the view context.
Voila - Django Forms with Bootstrap Modals! Spice up your UI!
I hope this helps somebody to solve a similar problem.
I wrote this simple AJAX that did the trick for me, hope it helps:
$(document).on('submit', 'div.modal-body form', function(e) {
var form_el = $(this);
e.preventDefault();
$.ajax({
type: $(this).attr('method'),
url: $(this).attr('action'),
data: $(this).serialize(),
success: function (xhr, ajaxOptions, thrownError) {
if ( $(xhr).find('.errorlist').length > 0 ) {
form_el.parents('.modal-body').html(xhr);
} else {
form_el.parents('.modal-body').html('<h4>Formulario enviado correctamente</h4>');
}
},
error: function (xhr, ajaxOptions, thrownError) {
form_el.parents('.modal-body').html(xhr);
}
});
});
Oh btw, you will also need something like this in order to load your form into the modal:
$('.modal-class').on('click',function(){
let dataURL = $(this).attr('data-href');
$('.modal-body').load(dataURL,function(){
$('#modal_crear').modal({show:true});
});
});