I have a django view and I'm expecting some of the data in the context to change a few times a second. Can I load a new context into the template after the response is sent without sending a new request? Thanks.
the view
def debug(request):
return render(request, 'all/debug.html', context={"x": x, "y": y})
the template
<div class="container">
<canvas id="data"></canvas>
<div class="graphing">
<select class="graph-select"></select>
<canvas id="graph" width="500"></canvas>
</div>
</div>
<script>
let y = "{{ y }}";
let x = "{{ x }}"
Chart.defaults.global.animation.duration = 0;
var ctx = document.getElementById('graph').getContext('2d');
var chart = new Chart(ctx, {
// The type of chart we want to create
type: 'line',
// The data for our dataset
data: {
labels: x.split` `.map(n => +n),
datasets: [{
label: 'My First dataset',
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: y.split` `.map(n => +n)
}]
},
// Configuration options go here
options: {
responsive: false,
}
});
</script>
What I want is to dynamically change the x and y data without sending a new request
you should use ajax tech in your template.
here you can find some informations.
just change the view to this
`
-
if somthing happens :
return render(request, 'all/debug.html', context={"z": z, "t": t})
else:
return render(request, 'all/debug.html', context={"x": x, "y": y})
return render(request, 'all/debug.html', context={"x": x, "y": y})
`
Related
I created a table in Django where upon doing row-click, the records for the corresponding row should be POSTED to the function "medicineRequestSelect" in view_doctor.py. However, it is unable to extract that row of values as shown in Image 1. It returns me None values.
I am relatively new to web development and any help or advice will be greatly appreciated!
<doctor_emr.html>
{% block mainbody%}
{% verbatim %}
<div id="app2" class="container">
<div class="emr-table">
<el-table
ref="multipleTable"
:data="list"
stripe
style="width: 50%"
#row-click="handle"
#selection-change="handleSelectionChange">
<el-table-column
prop="id"
label="Index">
</el-table-column>
<el-table-column
prop="order_id"
label="Order ID">
</el-table-column>
<el-table-column
prop="ward_number"
label="Ward No.">
</el-table-column>
<el-table-column
prop="prop"
label="Scan QR"
width="width">
<template slot-scope="{row$index}">
<el-button #click="onScanQR(row)" type="warning" icon="el-icon-camera" size="mini">Scan</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
{% endverbatim %}
<script>
new Vue({
el: '#app2',
data() {
return {
list: []
}
},
mounted() {
this.getemrList()
},
methods: {
getemrList() {
// Obtain EMR list
axios.post(ToDJ('emrList'), new URLSearchParams()).then(res => {
if (res.data.code === 0) {
console.log(res.data.data)
this.list = res.data.data
} else {
this.NotifyFail(res.data.data)
}
})
},
// Purpose: For the row click
handle(row, event, column) {
console.log(row, event, column)
axios.post(ToDJ('medicineRequestSelect'), new URLSearchParams()).then(res => {
if (res.data.code === 0) {
console.log(res.data.data)
this.list = res.data.data
let index = this.list.findIndex(item => {
return item.id == row.id
})
if (index == -1) {
this.$refs.multipleTable.toggleRowSelection(row, true);
this.list.push(row)
} else {
this.$refs.multipleTable.toggleRowSelection(row, false);
this.list.splice(index, 1)
}
} else {
this.NotifyFail(res.data.data)
}
})
},
onScanQR(row) {
this.dialogFormVisible = true;
this.tmForm={...row}
},
// Success notification
NotifySuc(str) {
this.$message({
message: str,
type: 'success'
})
},
// Error notification
NotifyFail(str) {
this.$message({
message: str,
type: 'warning'
})
}
}
})
</script>
{% endblock %}
<view_doctor.py>
#api_view(['GET',"POST"])
def medicineRequestSelect(request):
id = request.POST.get('id')
order_id = request.POST.get('order_id')
ward_number = request.POST.get('ward_number')
print("Values: ", id, order_id, ward_number)
return Action.success()
Image 1: Output Obtained
Image 2: Table I created
I'm also learning, and I try to progress by trying to help other's problem.
First where are you getting your data's from? From your Models?
So if I understood correctly you should import the model you want your data from and then make queries to it using your model.
model = TheNameOfYourModel.objects.all()
and then you can make your queries using q
PS: I'm still learning, i'm curious to see the answer of someone experienced
I am developing an application which shows the data created in a chartjs graph, what I am doing it does well, since all the data is displayed in the way I want, but I have a problem and that is that now I am trying to do that according to the type of graph that a user wants this to be changed, the problem is that the graph is changed but in case of having multiple graphs only the first graph is changed, the others continue with the graph by default, this is my template:
<select name="chartType" id="chartType" onchange="updateChart()" data-role="select">
<option value="pie">pie</option>
<option value="bar">Bar</option>
</select>
<canvas id="{{ project.slug }}" width="400" height="400"></canvas>
This is my script:
var faltante = 100 - {{ project.porcent }};
var data = {
labels: ['{{ project.name }}', 'Falta'],
datasets: [{
data: [{{ project.porcent }}, faltante],
backgroundColor: ['#252850', '#f44611']
}],
};
var ctx = document.getElementById('{{ project.slug }}').getContext('2d');
var myChart = new Chart(ctx, {
type: 'pie',
data: data
});
function updateChart() {
myChart.destroy();
myChart = new Chart(ctx, {
type: document.getElementById("chartType").value,
data: data
});
}
You can invoke your updateChart function with the selected chart type as follows:
onchange="updateChart(this.value)"
Everything could then be done inside the updateChart function.
destroy the chart if it already exists
create the new chart with the specified type
To make this work, you'll also have to explicitly invoke updateChart once with the initial chart type.
updateChart('pie');
Please take a look at below runnable code snippet and see how it works.
let myChart;
function updateChart(type) {
if (myChart) {
myChart.destroy();
}
myChart = new Chart('chart', {
type: type,
data: {
labels: ['A', 'B'],
datasets: [{
data: [3, 6],
backgroundColor: ['#252850', '#f44611']
}]
},
options: {
scales: {
yAxes: [{
display: type == 'bar',
ticks: {
beginAtZero: true
}
}]
}
}
});
}
updateChart('pie');
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
<select name="chartType" id="chartType" onchange="updateChart(this.value)" data-role="select">
<option value="pie">Pie</option>
<option value="bar">Bar</option>
</select>
<canvas id="chart" height="100"></canvas>
I sent an Ajax request to server to get some filtered data and here is a sample I receive from server:
(3) [{…}, {…}, {…}]
0: {id: 1, title: "12 Rue Longueil", slug: "12-rue-longueil", latitude: null, longitude: null, …}
1: {id: 2, title: "15 Rue Sherbrooke LM", slug: "15-rue-sherbrooke-lm", latitude: null, longitude: null, …}
2: {id: 3, title: "Cycle Neron", slug: "cycle-neron", latitude: "-73.5987000000000000", longitude: "45.4799000000000000", …}
length: 3
__proto__: Array(0)
above data is logged from console.
I want to display these data in HTMl tags within cards below.
but for that I need to use that received data and create children using JavaScript e.g. document.createElement('DIV'). and then place these data.
$(document).on('submit', "#filterform", function (e) {
e.preventDefault();
$.ajax({
type: 'GET',
url: "{% url 'listing:search' %}",
data: {
listing_for: $('#listing_for').val(),
// cutted
},
success: function (response) {
const listings = eval(response);
const content = document.getElementById('content');
for (let i = 0; i < listings.length; i++) {
const div = document.createElement('div');
div.className = 'listing mgb-1';
div.innerHTML = data[i].title;
content.appendChild(div);
// have to create, add lots of divs and classes
}
}
})
})
I was wondering if there is a way to sent Ajax request data as template variable? Or do I have to hardcode all HTML tags using Javascript?
Edit: Edited content based on first answer creating a separate HTML.
def search(request):
...
lst = list()
for listing in queryset:
ser = ListingSerializer(listing)
lst.append(ser.data)
return render(request, 'listing/newHtmlFile.html', {'listings': json.dumps(lst)})
separate HTML:
{% for list in listings %}
<div class="jumbotron">
<h1>{{ list.title }}</h1>
</div>
{% endfor %}
and ajax request:
success: function (response) {
document.querySelector('#content').insertAdjacentHTML('beforeend', response);
}
Yes, you can. Basically the idea is to make a separate HTML file that's going to be rendered by the view that handles the AJAX request. Then, you can use JavaScript and the insertAdjacentHTML() function to insert it in your original HTML file.
Take a look at this example:
view:
def ajax_handler(request):
# ... logic
return render(request, 'newHtmlFile.html', {'your_context': data})
Original HTML file
<div id='container'>
</div>
newHtmlFile.html
<p>{{ your_context }}</p>
JavaScript part (in this example I use Vanilla, not JQuery)
let ajax = new XMLHttpRequest();
ajax.onreadystatechange = function(){
if (this.readyState === 4){
if (this.status === 200){
document.querySelector('#container').insertAdjacentHTML('beforeend', this.responseText);
}
}
}
ajax.open('GET', '/ajax-handler-url', true);
ajax.send();
If you are interested to know how this works, we can break it down as follows:
You have some data (like a queryset, in your case) in your view
You call the render() method and you pass that data as the context data to a template
The render() method what actually does is to (let me be redundant here) render a HTML file (combining the HTML itself with the context data you passed) and return a HTTPResponse object containing a rendered text.
That rendered text (which is a bytestring that represents the content of the rendered HTML) is given as a response to the client. In this case, it's given specifically to the $.ajax() function that made the request.
We use the insertAdjacentHTML() function to append that rendered text to the desired element (in the example above, the #container div).
A quick, and possibly "dirty", way of doing it is to use the backtick strings in javascript:
success: function (r) {
const listings = JSON.parse(r); // with the correct headers from django, this should't be needed.
listings.forEach(e => $('#content').append(`
<div class="listing mgb-1">${e.title}</div>
`));
}
You should return your data from django with the appropriate headers so you automatically get json and don't need to eval(response).
I'm confused about how to do it via Ajax or Json, but how can I send the selection array (curCheck) on-click to Django views and receive it as a python array
javascript
document.getElementById('results').addEventListener('click', function(){
html_table = '<thead><tr><th>Currency</th><th>Amount</th><th>Symbol</th>><tr/><thead/>'
var checkElements = document.getElementsByClassName('ch');
for(var i =0; i< curname.length; i++){
if (checkElements[i].checked) {
var curChecked = curname[i];
var JsonArr = JSON.stringify(curChecked);
postcurChecked(JsonArr)
html_table += '<tr><td>' + curname[i] + '</td>';
}
}
document.getElementById('result_table').innerHTML = html_table;
},false;
ajax
function postsubChecked(curChecked) {
$.ajax({
"url": "http://127.0.0.1:8000/results/",
"type": "POST",
"data": {"checkbox": curChecked},
"headers": { 'X-CSRFToken': getCookie('csrftoken')}
})
}
in django
def currencyChecked(request):
body_unicode = request.body.decode('utf-8')
body_unicode = body_unicode.replace('%22','')
print(body_unicode) json_data = json.loads(body_unicode.read())
I would like to see the python array print to see it is passed to the back
but I keep getting this error:
json_data = json.loads(body_unicode.read()) AttributeError: 'str' object has no attribute 'read'
For getting the selected checkbox values and sending as an array using ajax you can use jquery like this:
consider you have multiple checkboxes and a button.
<input type="checkbox" name="imageName">
<input type="checkbox" name="imageName">
.......
<button id="deletePhoto">Delete</button>
after selecting multiple checkbox values click on this button. On clicking the below jquery will be triggered to make an arrya of selected checkbox values.
//jquery for getting the selelcted checkbox values
$(document).on("click","#deletePhoto",function(){
var favorite = [];//define array
$.each($("input[name='imageName']:checked"), function(){
favorite.push($(this).val());
});
alert("Photo Selected: " + favorite.join(", "));
if(favorite.length == 0){
alert("Select Photo to delete");
return false;
}
//ajax for deleting the multiple selelcted photos
$.ajax({type: "GET",
url: "/olx/deletePhotoFromEdit",
data:{
favorite:favorite
},
success: function(){
// put more stuff here as per your requirement
});
}
});
});
In the view you can get the array like this:
selected_photo = request.GET.getlist('favorite[]')
My objects are not being serialised correctly from my Django site when using Python's json.dumps(). I've got a class which is designed to make the injection of data into Chart.js components:
class ChartData:
def __init__(self):
self.labels = []
self.data = []
self.background_colours = []
self.hover_background_colours = []
def add_datum(self, label, datum, background_colour=None, hover_background_colour=None):
self.labels.append(label)
self.data.append(datum)
self.background_colours.append(background_colour)
self.hover_background_colours.append(hover_background_colour)
def get_converted_data(self):
return json.dumps({'labels': self.labels, 'data': self.data, 'background_colours': self.background_colours,
'hover_background_colours': self.hover_background_colours})
A calling method takes a Quiz as an input, and adds data from its associated Subject items:
def get_subject_chart_data(quiz):
subjects = Subject.objects.filter(question__quizquestion__quiz=quiz).distinct()
chart_data = ChartData()
for subject in subjects:
chart_data.add_datum(subject.name, subject.question_set.filter(quizquestion__quiz=quiz).count())
return chart_data.get_converted_data()
This converted data is then sent injected into the context for the page to be rendered.
def get_context_data(self, **kwargs):
context = super(QuizDetail, self).get_context_data(**kwargs)
quiz = self.get_object()
context['subject_chart_data'] = self.get_subject_chart_data(quiz)
return context
Following this, it's rendered into an {% include %} statement, being passed in as the chart_data argument:
{% include 'snippets/pie_chart.html' with chart_data=subject_chart_data chart_id='subject_chart' chart_height=400 chart_width=400 %}
Finally, the HTML renders the chart using the chart_data passed in:
<canvas id="{{ chart_id }}" width="{{ chart_width }}" height="{{ chart_height }}"></canvas>
<script>
var ctx = document.getElementById("{{ chart_id }}");
var chart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: {{ chart_data.labels|safe }},
datasets: [
{
data: {{ chart_data.data|safe }},
backgroundColor: {{ chart_data.background_colours|safe }}
}]
}
});
</script>
Given how I've seen json.dumps() used in the below example from Python docs, I would expect it to work.
>>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
'["foo", {"bar": ["baz", null, 1.0, 2]}]'
However, it turns out like this:
var chart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ,
datasets: [
{
data: ,
backgroundColor:
}]
}
});
However, if I pass each attribute of the ChartData to json.dumps(), as such:
def get_converted_data(self):
return {'labels': json.dumps(self.labels), 'data': json.dumps(self.data),
'background_colours': json.dumps(self.background_colours),
'hover_background_colours': json.dumps(self.hover_background_colours)}
It works with no problems:
var chart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ["Geo"],
datasets: [
{
data: [2],
backgroundColor: [null],
hoverBackgroundColor: [null]
}]
}
});
The second version of get converted data works because it is a dict and your template wants chartdata dot data and chart data dot background colours. The template is accessing the dict to get those values, which is why when you use a dict with json encoded values it works. The first version json encodes the whole dict as a string that the django template cannot read into.
You can transform your dict of python variables into a dict of json encoded variables like this:
data = {'labels': self.labels, 'data': self.data, 'background_colours': self.background_colours, 'hover_background_colours': self.hover_background_colours}
data_json = {k:json.dumps(v) for k, v in data.items()}