How to pass json dictionary from javascript .get to django template? - javascript

In the head of my django template I currently have:
<script>
$.get('get_students/', function (dict) {
alert(dict)
})
</script>
This alerts me of a json dictionary corresponding to dict, which comes from the following django view:
def get_students(request):
students = Student.objects.all()
students_json = serializers.serialize('json', students)
return HttpResponse(json.dumps(students_json), content_type='application/json')
Is it possible to "escape" dict from the script tag into the normal Django template so that I can iterate over it with something like:
{% for d in dict%}
<p>d.username</p>
{% endfor %}
If there is a more sensible way of doing this then please recommend it to me, I am still learning. Please note that I am working inside a component from which I have to call the view, which is why I am using js get.
Thanks!

Although it doesn't answer the question directly could this not be done by passing the data into the view with the get_context method instead then looping over it?
So your view would look this this:
class ExampleDetailView(DetailView):
model = Student
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['contextDictionary'] = get_students()
return context
then in the template have something like:
{% for d in contextDictionary %}
<p>d.username</p>
{% endfor %}

So the answer was to use JQuery. Inside the script tag I iterate over the dictionary values and append them to an innerHTML using a js string. So the .get above has to become something like:
$.get('get_students/', function (data) {
var write_to_div = document.getElementById("studentDiv");
for (var d in data) {
value = data[d]
write_to_div.innerHTML += "<p>" + value['first_name'] + "</p>"
}
})
This will append a paragraphs containing all the first names of all the Users to the div with id "studentDiv", so in the HTML template I have
<div id="studentDiv"></div>

Related

How do I send django object list to javascript?

I want to django query to javascript.so I changed queries to list. I sended list to javascript.But list were not displayed by console log.
class Comment_List_TV(ListView):
template_name = 'account/user_comment_list_tv.html'
def get_queryset(self):
Comment_list_query = list(Comment_tv.objects.none())
if self.request.user.is_authenticated:
Comment_list_query = list(Comment_tv.objects.filter(user=self.request.user))
print(Comment_list_query)
return Comment_list_query
Print display object list. But
const mydata = "{{Comment_list_query}}";
console.log(mydata);
Console log does not display django's object list.
why?
How do I send django object list to javascript?
Console log does return nothing because Comment_list_query in django template is called object_list, so you should use...
const mydata = "{{ object_list }}";
console.log(mydata)
But it won't work, because you probably needs parsed values.
So, you should write view like this:
#csrf_exempt
def get_comments(request):
comment_list_query = list(Comment_tv.objects.all())
return JsonResponse({'result': comment_list_query})
And receive it from AJAX call (for example using AJAX method from jQuery package).

How to pass several views return statements to one template in Django?

Currently I have one template file that displays some graph results based on one Django view, however, I would like to display in this same template another set of results from another function view. These are the details:
first function view - This works OK, sending values to the second function view and rendering the results into the template.
#api_view(['GET','POST',])
def tickets_results_test(request):
if request.method == "GET":
# ...do stuff...
return render(request, template_name, {'form': form})
elif request.method == "POST":
template_name = 'personal_website/tickets_per_day_results.html'
year = request.POST.get('select_year', None)
week = request.POST.get('select_week', None)
receive_send_year_week(year,week)
... rest of the code ...
data = {
"label_number_days": label_number_days,
"days_of_data": count_of_days,
}
my_data = {'my_data': json.dumps(data)}
return render(request, template_name, my_data)
second function view - I want to return these results into the template file.
def receive_send_year_week(year,week):
return year, week
template file - I want to show the results from the second function view below the You are currently reviewing:
{% extends "personal_website/header.html" %}
<script>
{% block jquery %}
var days_of_data = data.days_of_data
function setChart(){
....do stuff to generate graphs...
....
}
{% endblock %}
</script>
{% block content %}
<div class='row'>
<p>You are currently reviewing:</p>
</div>
<div class="col-sm-10" url-endpoint='{% url "tickets_per_day_results" %}'>
<div>
<canvas id="tickets_per_day" width="850" height="600"></canvas>
</div>
</div>
</div>
{% endblock content %}
How can I display the results from the second function view inside of the template? Do I need to heavily modify the first view?
I want to display those two values in the html, I want to write them
in the html file. How can invoke them if you say that I already have
them?
You can simply place it in your data dict, this is, if the code you provided works partially, I can't test it right now, but you will get the gest of it:
template_name = 'personal_website/tickets_per_day_results.html'
year = request.POST.get('select_year', None)
week = request.POST.get('select_week', None)
data = {
"label_number_days": label_number_days,
"days_of_data": count_of_days,
"year": year,
"week": week,
}
Then in your template:
var year = data.year
var week = data.week
I think I see what you want to do, altough it is not clear, as pointed by others.
Your view is an api view, so you might not be wanting to deal with a django template. You should probably make an Ajax call to this view and replace 'render' by JsonResponse in this case.
The other way is doing simple django stuff and use its template. So you should get rid of the 'if POST GET' and decorator parts (I don't see any POST request anyway) of your view, and anywhere in your template use {{my_data}} to print your data. To access count_of _days define in the view, you can do {{my_data.days_of_data}}.
Things to undertstand here are:
django template renders a html with data that you send through a dictionary (my_data). You can access this data with the double curly brackets notation in your template.
Django views can be used as api endpoints. In that case you make an Ajax request and the view should return a json object to be handled by Ajax. No mention to any template whatsoever in the view.
Hope it helps!

Using list from views in Django 1.8.1 as an array in javascript template

I have a piece of code in views.py that gets the file names from a directory:
def imgArray(request):
filepath = STATIC_PATH+"\\images"
imageArray=[]
ext='.jpg'
for i in os.listdir(filepath):
if(os.path.splitext(i)[1] == ext):
imageArray.append( i )
context = {'imageArray': imageArray}
print context
return render(request, 'imgpage/add_category.html',context)
def add_category(request):
# A HTTP POST?
if request.method == 'POST':
#Do some actions
else:
# If the request was not a POST, display the form to enter details.
imageArray = imgArray(request)
return render(request, 'imgpage/add_category.html')
I want to use this array of image files in javascript. I want to use the array of file names so that I can use js to change image source.
The print context statement yields the following output in the python console:
{'imageArray': ['image0.jpg', 'image1.jpg', 'image2.jpg', 'image3.jpg', 'image4.
jpg', 'image5.jpg', 'image6.jpg', 'image7.jpg', 'image8.jpg', 'image9.jpg']}
But I am not able to access the imageArray at all in the template. Here are the scripts I tried to test if the array has been passed, in the template html file:
In add_category.html file:
{% for img in imageArray %}
<li>{{ img|safe }}</li>
<li>{{ img }}</li>
<p>img</p>
{% endfor %}
Also, note that the "img" inside <p> tags are also not rendered on the screen.
<script type="text/javascript">
var images = "{{imageArray|safe}}";
console.log(images);
console.log("imgx="+images[1]);
document.getElementsByTagName("img")[0].src = DJANGO_STATIC_URL+images[2];
</script>
In the above script, the first console log prints empty line in the console, while the 2nd prints "imgx=undefined"
Please suggest me ways I can use the python list as JS array. I use Django 1.8.1, but the service I would host on uses 1.7.x. So something that would work on both would be great.
You have a very peculiar structure here. imageArray() is a view, which returns a full HttpResponse; but you call it from within another view, add_category. What's more, you do nothing at all with the result; it is thrown away and never passed anywhere. So, naturally, it's always going to be blank in the template.
I'm not sure exactly what you're doing, so it's hard to know what you really want here. But I suspect that imageArray() should be a normal utility method, which simply returns a list of images:
def imgArray():
filepath = os.path.join(STATIC_PATH, "\\images")
images =[f for f in os.listdir(filepath) if f.endswith('.jpg')]
return images
Then you need to actually do something with that value in your add_category function:
def add_category(request):
...
else:
imageArray = imgArray()
return render(request, 'imgpage/add_category.html', {imageArray: imageArray})
So here is what I did:
views.py
#importing json
import json
from django.core.serializers.json import DjangoJSONEncoder
def imgArray(request):
filepath = STATIC_PATH+"\\images"
imageArray=[]
ext='.jpg'
for i in os.listdir(filepath):
if(os.path.splitext(i)[1] == ext):
imageArray.append( i )
json_list = json.dumps(list(imageArray), cls=DjangoJSONEncoder)
return json_list
def add_category(request):
# A HTTP POST?
if request.method == 'POST':
#Do something
else:
# If the request was not a POST, display the form to enter details.
imageArray = imgArray(request)
context = {'imageArray': imageArray}
return render(request, 'imgpage/add_category.html',context)
return render(request, 'imgpage/add_category.html')
And in add_category.html:
<script type="text/javascript">
var images = {{imageArray|safe}};
document.getElementsByTagName("img")[0].src = DJANGO_STATIC_URL+"images/"+images[1];
</script>
Hope this helps someone :)
Cheers!

Sending JSON data as context quotes becoming "?

I am trying to send some schedule data to a webpage using Django and JSON format. My view to send this data looks like this:
def sessionscheduler(request):
c = connection.cursor()
c.execute("SELECT * FROM meter_schedule WHERE id = 1")
scheduleArray = []
for row in c.fetchall():
data = dict([('lastUpdate',row[1]), ('weekdaysOn',row[2]), ('weekdayChargeRateOffPeriodKwh',row[3]), ('weekdayEveningChargeOn',row[4]), ('weekdayEveningStart',row[5]),
('weekdayEveningDuration',row[6]), ('weekdayDayChargeOn',row[7]), ('weekdayDayStart',row[8]), ('weekdayDayDuration',row[9]), ('weekendsOn',row[10]),
('weekendChargeRateOffPeriodKWh',row[11]), ('weekendEveningChargeOn',row[12]), ('weekendEveningStart',row[13]), ('weekendEveningDuration',row[14]),
('weekendDayChargeOn',row[15]), ('weekendDayStart',row[16]), ('weekendDayDuration',row[17])])
scheduleArray.append(data)
jscheduleArray = json.dumps(scheduleArray)
context = {'jscheduleArray' : jscheduleArray}
return render(request, 'sessionscheduler.html', context)
I have used a template to render what is in jscheduleArray and it is coming out exactly how I want on the HTML page. However I want to use this data in my JavaSript file. The problem is that the quotes are not "" in the page source they are " which the script does not like. How do I fix this. Also I have a separte js file, is there anyway to directly call the JSON object into the the .js file? I am using YUI and pure JS.
I think you can use autoescape tag in your template to not escape the quotes
# sessionscheduler.html
{% autoescape off %}
{{ your_string }}
{% endautoescape %}

How to pass a list from Python, by Jinja2 to JavaScript

Let's say I have a Python variable:
list_of_items = ['1','2','3','4','5']
and I pass it to Jinja by rendering HTML, and I also have a function in JavaScript called somefunction(variable). I am trying to pass each item of list_of_items. I tried something like this:
{% for item in list_of_items %}
<span onclick="somefunction({{item}})">{{item}}</span><br>
{% endfor %}
Is it possible to pass a list from Python to JavaScript or should I pass each item from list one by one in a loop? How can I do this?
To pass some context data to javascript code, you have to serialize it in a way it will be "understood" by javascript (namely JSON). You also need to mark it as safe using the safe Jinja filter, to prevent your data from being htmlescaped.
You can achieve this by doing something like that:
The view
import json
#app.route('/')
def my_view():
data = [1, 'foo']
return render_template('index.html', data=json.dumps(data))
The template
<script type="text/javascript">
function test_func(data) {
console.log(data);
}
test_func({{ data|safe }})
</script>
Edit - exact answer
So, to achieve exactly what you want (loop over a list of items, and pass them to a javascript function), you'd need to serialize every item in your list separately. Your code would then look like this:
The view
import json
#app.route('/')
def my_view():
data = [1, "foo"]
return render_template('index.html', data=map(json.dumps, data))
The template
{% for item in data %}
<span onclick=someFunction({{ item|safe }});>{{ item }}</span>
{% endfor %}
Edit 2
In my example, I use Flask, I don't know what framework you're using, but you got the idea, you just have to make it fit the framework you use.
Edit 3 (Security warning)
NEVER EVER DO THIS WITH USER-SUPPLIED DATA, ONLY DO THIS WITH TRUSTED DATA!
Otherwise, you would expose your application to XSS vulnerabilities!
I had a similar problem using Flask, but I did not have to resort to JSON. I just passed a list letters = ['a','b','c'] with render_template('show_entries.html', letters=letters), and set
var letters = {{ letters|safe }}
in my javascript code. Jinja2 replaced {{ letters }} with ['a','b','c'], which javascript interpreted as an array of strings.
You can do this with Jinja's tojson filter, which
Dumps a structure to JSON so that it’s safe to use in <script> tags [and] in any place in HTML with the notable exception of double quoted attributes.
For example, in your Python, write:
some_template.render(list_of_items=list_of_items)
... or, in the context of a Flask endpoint:
return render_template('your_template.html', list_of_items=list_of_items)
Then in your template, write this:
{% for item in list_of_items %}
<span onclick='somefunction({{item | tojson}})'>{{item}}</span><br>
{% endfor %}
(Note that the onclick attribute is single-quoted. This is necessary since |tojson escapes ' characters but not " characters in its output, meaning that it can be safely used in single-quoted HTML attributes but not double-quoted ones.)
Or, to use list_of_items in an inline script instead of an HTML attribute, write this:
<script>
const jsArrayOfItems = {{list_of_items | tojson}};
// ... do something with jsArrayOfItems in JavaScript ...
</script>
DON'T use json.dumps to JSON-encode variables in your Python code and pass the resulting JSON text to your template. This will produce incorrect output for some string values, and will expose you to XSS if you're trying to encode user-provided values. This is because Python's built-in json.dumps doesn't escape characters like < and > (which need escaping to safely template values into inline <script>s, as noted at https://html.spec.whatwg.org/multipage/scripting.html#restrictions-for-contents-of-script-elements) or single quotes (which need escaping to safely template values into single-quoted HTML attributes).
If you're using Flask, note that Flask injects a custom tojson filter instead of using Jinja's version. However, everything written above still applies. The two versions behave almost identically; Flask's just allows for some app-specific configuration that isn't available in Jinja's version.
To add up on the selected answer, I have been testing a new option that is working too using jinja2 and flask:
#app.route('/')
def my_view():
data = [1, 2, 3, 4, 5]
return render_template('index.html', data=data)
The template:
<script>
console.log( {{ data | tojson }} )
</script>
the output of the rendered template:
<script>
console.log( [1, 2, 3, 4] )
</script>
The safe could be added but as well like {{ data | tojson | safe }} to avoid html escape but it is working without too.
I can suggest you a javascript oriented approach which makes it easy to work with javascript files in your project.
Create a javascript section in your jinja template file and place all variables you want to use in your javascript files in a window object:
Start.html
...
{% block scripts %}
<script type="text/javascript">
window.appConfig = {
debug: {% if env == 'development' %}true{% else %}false{% endif %},
facebook_app_id: {{ facebook_app_id }},
accountkit_api_version: '{{ accountkit_api_version }}',
csrf_token: '{{ csrf_token }}'
}
</script>
<script type="text/javascript" src="{{ url_for('static', filename='app.js') }}"></script>
{% endblock %}
Jinja will replace values and our appConfig object will be reachable from our other script files:
App.js
var AccountKit_OnInteractive = function(){
AccountKit.init({
appId: appConfig.facebook_app_id,
debug: appConfig.debug,
state: appConfig.csrf_token,
version: appConfig.accountkit_api_version
})
}
I have seperated javascript code from html documents with this way which is easier to manage and seo friendly.
you can do it
<tbody>
{% for proxy in proxys %}
<tr>
<td id={{proxy.ip}}>{{proxy.ip}}</td>
<td id={{proxy.port}}>{{proxy.port}}</td>
<td>{{proxy.protocol}}</td>
<td>{{proxy.speed}}</td>
<td>{{proxy.type}}</td>
<td>{{proxy.city}}</td>
<td>{{proxy.verify_time}}</td>
<td>
<button type="button" class="btn btn-default" aria-label="Left Align">
<span class="glyphicon glyphicon-paste" aria-hidden="true" onclick="copyProxy('{{proxy.ip}}', '{{proxy.port}}')"></span>
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
Make some invisible HTML tags like <label>, <p>, <input> etc. and name its id, and the class name is a pattern so that you can retrieve it later.
Let you have two lists maintenance_next[] and maintenance_block_time[] of the same length, and you want to pass these two list's data to javascript using the flask. So you take some invisible label tag and set its tag name is a pattern of list's index and set its class name as value at index.
{% for i in range(maintenance_next|length): %}
<label id="maintenance_next_{{i}}" name="{{maintenance_next[i]}}" style="display: none;"></label>
<label id="maintenance_block_time_{{i}}" name="{{maintenance_block_time[i]}}" style="display: none;"></label>
{% endfor%}
Now you can retrieve the data in javascript using some javascript operation like below -
<script>
var total_len = {{ total_len }};
for (var i = 0; i < total_len; i++) {
var tm1 = document.getElementById("maintenance_next_" + i).getAttribute("name");
var tm2 = document.getElementById("maintenance_block_time_" + i).getAttribute("name");
//Do what you need to do with tm1 and tm2.
console.log(tm1);
console.log(tm2);
}
</script>

Categories

Resources