Sending JSON data as context quotes becoming "? - javascript

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 %}

Related

How to use javascript variable in django if statement (template)?

I'm trying to update my html element with django if statement:
element.innerHTML= `{% if person.name == ${value} %} something {% endif %}`
but I receive an error:
TemplateSyntaxError at /
Could not parse the remainder: '${value}' from '${value}'
I also tried:
`{% if person.name == ${value} %} something {% endif %}`
But the statement doesn't work properly.
Is there anything I can do to combine javascript with Django variables?
Short Answer
No. You can not do this, at least not that easily.
Detailed (slightly) Answer
Django replaces all tags, {{ }} and {% %} with the result at the server (back end) end when the page is rendered, before it gets to the client. Your JavaScript (JQuery?) variable is evaluated by the client (the front end). Django will not know what ${value} is. So, no, you can not use a JavaScript variable in Django template code.
This does not mean you can not achieve what you want, but it must be done in the following way. Your JavaScript code can fetch the value of person.name from a view and then you can do your if statement in the JavaScript file after the response from the fetch is received. The view could return the value of person.name as a JsonResponse

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

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>

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!

How to set a jinja2 expression with a Javascript variable?

How can I use a Jinja2 expression within a js function? I'd tried something similar to the lines below and the expression isn't working. The attribute fileList used in response is a list coming from flask through Json.
var response = JSON.parse(req.responseText);
{% set myFiles = response.fileList %}
Jinja2 is a templating language. Meaning all template expressions will be evaluated and replaced by either text or HTML code before even served to the client.
Whereas Javascript is a scripting language used on the client side.
So there is actually no way to pass any values to a Jinja2 expression from Javascript as there simply don't exist any Jinja2 expressions on the client side because they have all been replaced already by text or html code.
However if you simply want to pass any data from client to server there are a lot of ways to do that. Probably the most fitting for you would be an Ajax call.
I think you looking for including expression or statement in js.
It's possible, use double quotes(" "). One thing you can't directly add in the js file. use your code at the end of the code
var response = JSON.parse(req.responseText);
"{% set myFiles = response.fileList %}"
For Clear Understanding,
app.py
#app.route('/')
def home():
return render_template('index.html',check=0,text='hai')
index.html
<div>
.
.
.
</div>
<script>
var text = {{ text }} //Throws error
var text = "{{ text }}" //console it
{% if(check == 0) %}
console.log('its true')
{% endif %} //Throw error
"{% if(check == 0) %}"
console.log('its true')
"{% endif %}"//Success
</script>
It's working for me. vote if works

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