I have a list passed through the context into the html page of a Django project which I want to read inside of a .js which contains chartjs code. The problem is that .js is reading as string and not as a list/array.
views.py
def index(request):
context = {
"data": [1, 2, 3, 4, 5]}
return render(request, 'index.html', context)
Then, in the html page I have to pass the {{ data|safe }} to a javascript like so:
<script src='{% static "js/chart.js/linechart.js" %}'
var label = "fakelabel";
var index = {{ data|safe }};
></script>
Inside the .js I'm reading the 'index' input as:
document.currentScript.getAttribute("index")
How can I fix this? ('label' is read correctly as str indeed).
{{ data|safe }} is not a safe way to output a Python object as JavaScript.
Use json_script if you want to be safe
This is how to do it.
Write your object as json:
data = {'numbers':['1', '2', '3', '4', '5']}
def index(request):
context = {"data": data}
return render(request, 'index.html', context)
<script>
var index = {{ data|json_script:'mydata' }};
<script>
Then you can use the index variable into another scrip like this:
<script>
const data = JSON.parse(document.getElementById('mydata').textContent);
mydata = data['numbers'];
</script>
You could (and probably should) point to an external JavaScript file rather than using embedded JavaScript.
read here for more details
You can use ajax to fetch list or dict data from views and you need to add jQuery cdn in html file.
from django.http import JsonResponse
def indexAjax(request):
context={"data":[1,2,3,4,5]}
return JsonResponse(context,safe=False)
Inside your js file or script tag
function fun(){
$.ajax({
url:"{% url'indexAjax" %},
dataType:'json',
type:'GET',
success:function(res){
console.log(res.data)
//here you can write your chartjs
}
})}
The correct way to fix the above problem is:
views.py
def index(request):
context ={"data": [1, 2, 3, 4, 5]}
return render(request, 'index.html', context)
charts.html
Then, in the html script you should add {{ data|json_script:"index" }} like you you do with the 'static' tag. Then, always in your .html script you do not need to pass the 'index' list. Therefore when you call the javascript inside your .html you just need to pass:
{{ data|json_script:"index" }}
<script src='{% static "js/chart.js/linechart.js" %}'
var label = "fakelabel";
></script>
js/chart.js/linechart.js
Finally, inside you separate javascript (in this case "js/chart.js/linechart.js"), we can fetch the list with:
JSON.parse(document.getElementById('index').textContent)
Related
views.py
def somefunction(request):
var = True
return render(request, dasboard.html)
myfirst.js
function myFunction() {
}
How I get var from views.py into the myfirst.js function?
It isn't possible to give a 100% correct answer without knowing the templating engine you are using (DTL, Jinja2?). However, if var doesn't contain any sensitive/private data, the general solution is to pass var to your html template through the context parameter of the render function:
# views.py
views.py
def somefunction(request):
var = True
context = { "var": var }
return render(request, dasboard.html, context)
Then, expose var as a data-* attribute on a html element in your template (the exact implementation will change based on the templating engine you are using):
<!-- dashboard.html -->
<div id="info" data-var="{{ var }}" >
...
</div>
Finally, in your javascript file, you simply retrieve the same html element and access var through the special dataset property:
// myfirst.js
function myFunction() {
var infoElement = document.getElementById("info");
var varValue = infoElement.dataset.var;
}
I have a django project that I'm trying to add a custom "online" state to (boolean field in a model). I want to refresh a div periodically to show if a user is now online. The div which is refreshed, with the class button-refresh, is in an included HTML file.
The issue is that the include doesn't work with my for loop in the original HTML file, none of the "professionals" data is retrieved from the server. I'm pretty new to django, my assumption is that the refresh_professionals.html file is retrieved with the ajax request and is entirely separate from the all_professionals.html and then included, without ever being a part of the for loop meaning that the {{ professional.professional_profile.online }} syntax doesn't work.
Any ideas on how to fix this issue? If there is a better way to do this, let me know. Thanks.
all_professionals.html
{% for professional in professionals %}
...
{{ professional.name }}
{% include 'professionals/refresh_professionals.html' %}
...
{% endfor %}
...
{% block postloadjs %}
{{ block.super }}
<script>var global_url = "{% url 'refresh_professionals' %}";</script>
<script src="{% static 'professionals/js/professionals.js' %}"></script>
{% endblock %}
refresh_professionals.html
<div class="col button-refresh">
{% if professional.professional_profile.online is True %}
<p class="custom-button mb-1 w-25 mx-auto">Chat</p>
{% else %}
<p class="custom-button-disabled mb-1 w-25 mx-auto">Unavailable</p>
{% endif %}
<p>{{ professional.price_chat }}/min</p>
</div>
professionals.js
$(document).ready(function(){
setInterval(function() {
$.ajax({
url: global_url,
type: 'GET',
success: function(data) {
$('.button-refresh').html(data);
}
});
}, 5000)
});
urls.py
urlpatterns = [
path('', views.view_all_professionals, name='view_all_professionals'),
path('refresh/', views.refresh_professionals, name='refresh_professionals'),
]
views.py
def view_all_professionals(request):
"""A view to return the professionals page"""
professionals = Professional.objects.all()
languages = Languages.objects.all()
context = {
'professionals': professionals,
'languages': languages,
}
return render(request, 'professionals/all_professionals.html', context)
def refresh_professionals(request):
"""A view to refresh the online button section"""
professionals = Professional.objects.all()
context = {
'professionals': professionals,
}
return render(request, 'professionals/refresh_professionals.html', context)
EDIT
I've followed Daniel's advice and am now returning a JSON object. This is the updated code
professionals.js
$(document).ready(function(){
setInterval(function() {
$.ajax({
url: global_url,
type: 'GET',
success: update_professionals,
});
}, 5000)
});
function update_professionals(response){
// unpack the response (context) from our view function:
var professionals = response.professionals;
// update html:
var i;
for (i = 0; i < professionals.length; i++) {
$('#professional-name' + i).text('professionals.name' + i);
};
};
views.py
def refresh_professionals(request):
"""A view to refresh the professionals section page"""
professionals = Professional.objects.all()
professionals = serializers.serialize("json", professionals)
context = json.dumps({
'professionals': professionals,
})
return HttpResponse(context)
The issue I'm facing now is referencing the professionals data. It's returning uncaught errors. The forloop is necessary because in my HTML I've got a series of IDs with a number attached to the end using a django forloop.counter. Any advice would be appreciated. Thanks.
Okay, lets assume we have a view function like so:
from django.http import HttpResponse
import json
def refresh_professionals(request):
"""A view to refresh the online button section"""
professionals = Professional.objects.all()
# convert to json friendly format:
professionals = ...
context = json.dumps({
'professionals': professionals,
})
return HttpResponse(context)
This assumes professionals now looks something like (the actual structure will obviously be different):
professionals = {"id":1, "name":"Jason"}
Now, in our js file we should have an ajax request like so (wrapped in a setInterval method, etc.):
$.ajax({
url: global_url,
type: 'GET',
success: update_professionals, // reference to an ajax-success function
});
And our success function like so:
update_professionals(response) {
// unpack the response (context) from our view function:
// use JSON.parse() to convert a string to json
var professionals = JSON.parse(response.professionals);
// update html:
$('#professional-name').text(professionals.name)
}
This assumes we have an HTML element like so:
<div id="professionals-name"> Sue </div>
The difference is we are using js to update the HTML on the fly instead of trying to re-render an HTML template likely will require a page refresh.
I have multiple apps in project and using appname and namespace for
urls. I need to dynamically add js variable value in django template
url with app name. If I write without appname like --
var temp =23
var href = "{% url 'report_page' id=0 %}".replace(/0/, temp.toString())
It is giving desired result as--
"{% url 'report_page' location_id=23 %}"
But when I use appname its not working for me e.g
var href = "{% url 'appname : report_page' id=0 %}".replace(/0/, temp.toString())
Let me give you the exact code: In django template:
<html>
Report
</html>
var href = "{% url 'appname : report_page' id=0 %}".replace(/0/, temp.toString())
In url.py of the appname:
appname = 'appname'
urlpatterns = [
url(r'^report-page$', views.report_page, name='report_page'),
url(r'^report-page/(?P<id>[0-9]+)$', views.report_page, name='report_page'),
]+ static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
In views:
def report_page(request):
import pdb;pdb.set_trace()
# location_id = request.GET['id']
return render(
request,
'report.html',
{'id' : request.user.id, 'id' : ''}
)
Note: I'm using django 1.11 and I have also tried below one but getting empty string:
var temp =$('#check_id').val() <a href="{% url 'appname: report_page' %}?id="+temp;>Report</a>
When you are using with djagno url such as {% url 'appname : report_page' id=0 %}, when django template will rendering it will convert into the like /appname/report-page/0/,
it's solutions is,
first you will to take a tag attributes value then change this.
please find below solutions.
var arr = $("a").attr('href').split('/')
arr[arr.length-2]=777 # demo value
$("a").attr('href',arr.join('/'))
I have a Python function that returns some value. Also I connected to my project Google Charts. So I need to pass that value to a js function in html file of Google Charts. The project is on Django btw.
What is the most correct way to do this?
{% extends "gappi_tmp/wrapper.html" %}
{% block content %}
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Task', 'Hours per Day'],
['lol',11], // The variable should be here, instead of '11'
['Eat', 11] // Here another variable
]);
var options = {
title: 'Inbox | Outbox'
};
var chart = new google.visualization.PieChart(document.getElementById('piechart'));
chart.draw(data, options);
}
</script>
</head>
<body>
<div style="padding-top: 5px; background: cornflowerblue; width: auto; height: 300px;" id="piechart"></div>
</body>
{% endblock %}
You should render your template with a context:
https://docs.djangoproject.com/en/2.0/ref/templates/api/#rendering-a-context
The method of passing the context to the template depends on how your views are written.
Function-based views
Pass the context dictionary to the render() function:
https://docs.djangoproject.com/en/2.0/topics/http/shortcuts/#optional-arguments
from django.shortcuts import render
def my_view(request):
# View code here...
context = {'foo': 'bar'}
return render(request, 'myapp/index.html', context=context)
Class-based views
Write your own implementation of the add_context_data() method: https://docs.djangoproject.com/en/2.0/topics/class-based-views/generic-display/#adding-extra-context
from django.views.generic import DetailView
from books.models import Book, Publisher
class PublisherDetail(DetailView):
model = Publisher
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
# Add in a QuerySet of all the books
context['book_list'] = Book.objects.all()
return context
Once you passed key: value context to the template, you should use it in the template like this: {{ key }}.
https://docs.djangoproject.com/en/2.0/topics/templates/#variables
<script type="text/javascript">
var a = "{{ key|escapejs }}";
</script>
escapejs template filter is required to prevent possible XSS vulnerabilities. If you need to pass JSON, you could check out Django ticket #17419
In case you want to access python vars in a separated js file. You can define js global vars with the value of python vars, then access those global vars in a separated js file.
Generate the above page dynamically in Django including the necessary json data object from your python code
from here
In case that you have you js file inside your html file, and not in a seperated js file, since variables passed through context are available in the rendering templates, you can proceed that way.
After sending all the variables via context to template.
var jsVariable = '{{django_value}}';
var data = google.visualization.arrayToDataTable([
['Task', '{{ task_variable }}'], // as string
['lol',{{lol_variable}}], // as integer
['Eat', {{eat_variable}} ]
]);
You can also loop through.
var data = google.visualization.arrayToDataTable([
{% for item in queryset %} // {% for item in json_response %}
['Task', '{{ task.attribute }}'],
{% endfor %} // {% endfor %}
]);
Basically, you must know that you can use it, it depends of what you really want to do.
I am using Vue.js for the first time. I need to serialize the objects of django
views.py
def articles(request):
model = News.objects.all() # getting News objects list
modelSerialize = serializers.serialize('json', News.objects.all())
random_generator = random.randint(1,News.objects.count())
context = {'models':modelSerialize,
'title' : 'Articles' ,
'num_of_objects' : News.objects.count() ,
'random_order' : random.randint(1,random_generator) ,
'random_object' : News.objects.get(id = random_generator ) ,
'first4rec' : model[0:4],
'next4rec' : model[4:],
}
return render(request, 'articles.html',context)
I have tried to display serialized json data in html its working fine there,
Now , how to intialize json data in vue instance and to access in html using v-repeat attribute.
https://jsfiddle.net/kn9181/1yy84912/
Please can any one help???
A simple example.
views.py
def articles(request):
context {
'articles' : ['a1','a2','a3']
}
return render(request, 'articles.html', context)
articles.html
{% verbatim %}
<div id="app">
<ul>
<li v-for="a in articles">{{ a }}</li>
</ul>
</div>
{% endverbatim %}
<script>
new Vue({
el : "#app",
data : function(){
return {
articles : {{ articles | safe }}
}
}
})
</script>
Things to watch out for :
The verbatim tag to stop Django from rendering the contents of this block tag since Vue uses the same interpolating symbols.
The safe filter to prevent Django from escaping the contents.
If you are passing a dictionary, consider turning it into JSON first
Generally speaking, prefer passing data to Vue via Ajax