Ajax request to changing boolean value of object in django - javascript

i'm struggling to make ajax function that change the boolean value of an object without refreshing the page.
It returns error 500.
Model:
class Donation(models.Model):
is_taken = models.BooleanField(default=False)
HTML:
<div style="width: 50%; float:left" class="steps--container">
{% for d in taken %}
<div style="width: 80%; float: left">
<h4>{{d.quantity}} bags of {% for c in d.categories.all %} {{c}} {% endfor %} by {{d.user.first_name}} {{d.user.last_name}} </h4>
<input type="text" id="donation_id" value={{d.id}} hidden>
</div>
<div style="width: 20%; float:right">
<input type="button" onclick="updateStatus()" value="{{d.id}}" Mark as not taken>
</div>
<br>
{% endfor %}
</div>
JS:
function updateStatus() {
var dId = document.getElementById("donation_id").value;
var dIdInt = parseInt(dId, 10)
$.ajax({
type: "GET",
url: "/ajax/taken_or_not_taken/",
data: {
"donation_id": dIdInt
}
}).done(function(e){
console.log("done")
console.log(dIdInt)
})
.fail(function(e){
console.log('error')
console.log(e)
})
}
View:
def taken_or_not_taken(request):
obj = request.GET.get('donation_id', '')
print(obj)
return JsonResponse(obj)
Url:
url(r'^ajax/taken_or_not_taken/$', views.taken_or_not_taken, name='taken_or_not_taken'),
How can i make it works?

The full stacktrace says :
line 121, in taken_or_not_taken return JsonResponse(obj)
line 555, in __init__'In order to allow non-dict objects to be serialized set the the safe parameter to False.'
JsonResponse() should have a dict in argument and you pass an integer.
You can use the donation_id name:
def taken_or_not_taken(request):
obj = request.GET.get('donation_id', '')
print(obj)
return JsonResponse({'donation_id':obj})
Or use the safe=False parameter : https://docs.djangoproject.com/en/3.1/ref/request-response/#django.http.JsonResponse

Yea, i found it out, thanks guys anyway,
But the new problem appeared.
User still needs refresh the page to see the changes.
How to do it without refreshing page? Can i do it in django view?
Like:
def taken_or_not_taken(request):
obj = request.GET.get('donation_id')
data = {
"id": obj
}
donate = Donation.objects.get(id=obj)
if donate.is_taken == True:
donate.is_taken = False
donate.save()
elif donate.is_taken == False:
donate.is_taken = True
donate.save()
return JsonResponse(data)

You can use ajax "POST" method to send the query to the server without refreshing the page.
$.ajax({
type: "POST",
url: "url_of_query",
data: {
// Data you want to update
}
success: function(){
console.log("Success msg");
},
error: function(){
console.log("error");
},
)}

Related

How do I get a variable value from javascript function to python function in django

I am trying to scan QR code using html,javascript as shown below by nurse_home.html. I am able to scan and see the content of the QR code on the website but I can't POST the QR code output represented by
<output type='POST' id='result' name='result' placeholder='qrCodeMessage'>
in nurse_home.html.
I want to post it to the python function: nurse_qrscan in views_nurse.py so that it can be written into the database
Any help is greatly appreciated!
The following are the relevant codes:
<nurse_home.html>
{% load static %}
{% block mainbody %}
<title>Django Online Barcode Reader</title>
<meta charset="utf-8">
{% csrf_token %}
<script src={% static "js/html5-qrcode.min.js" %}></script>
<style>
.result{
background-color: green;
color:#fff;
padding:20px;
}
.row{
display:flex;
}
</style>
{% csrf_token %}
<div class="row">
<div class="col">
<div style="width:500px;" id="reader"></div>
</div>
<div class="col" style="padding:30px;">
<h4>Scanned Result</h4>
<!--<div id="result" name="result">Result Here</div>-->
<output type="POST" id="result" name="result" placeholder="qrCodeMessage">
{% csrf_token %}
</div>
</div>
<script type="text/javascript">
function onScanSuccess(qrCodeMessage) {
document.getElementById('result').innerHTML = '<span class="result">'+qrCodeMessage+'</span>';
}
function onScanError(errorMessage) {
//handle scan error
}
var html5QrcodeScanner = new Html5QrcodeScanner(
"reader", { fps: 10, qrbox: 250 });
html5QrcodeScanner.render(onScanSuccess, onScanError);
</script>
{% endblock %}
Edited <script> tag
function getCookie(name) {
let cookie = document.cookie.match("(^|;) ?" + name + "=([^;]*)(;|$)");
return cookie ? cookie[2] : null;
}
function onScanSuccess(qrCodeMessage) {
document.getElementById("result").innerHTML = '<span class="result">' + qrCodeMessage + "</span>";
sendQrCode(qrCodeMessage);
}
async function sendQrCode(qrCode) {
const response = await fetch("/nurse_qrscan", {
method: "POST",
headers: {
"X-CSRFToken": getCookie("csrftoken"),
},
body: JSON.stringify({
result: qrCode,
}),
})
.then((response) => response.json())
.then((data) => {
console.log(data)
axios.post(ToDJ("nurse_qrscan")) //**Newly added**
}
);
}
function onScanError(errorMessage) {
//handle scan error
}
var html5QrcodeScanner = new Html5QrcodeScanner("reader", {
fps: 10,
qrbox: 250,
});
html5QrcodeScanner.render(onScanSuccess, onScanError);
<views.py>
def nurse_home(request):
return render(request, 'nurse_home.html')
<views_nurse.py>
#api_view(['GET',"POST"])
# Nurse scans QR
def nurse_qrscan(request):
### Test! nurse: QR
if request.method == 'POST':
print("Hi")
result = request.POST.get("result")
print(result)
# Saving the result to database, nurse_QR
# c = connection.cursor()
# c.execute("INSERT INTO nurse_QR (output) VALUES ('{0}');".format(result))
return Action.success()
<urls.py>
from hospital import view_nurse
from . import views
urlpatterns = [
# Main Page
path('', views.login, name='login'),
path('nurse/', views.nurse_home),
path('nurse_home/', views.nurse_home),
# Nurse
path('nurseLogin', view_nurse.nurseLogin, name='nurseLogin'),
path('nurse_qrscan', view_nurse.nurse_qrscan, name='nurse_qrscan'),
]
Actual database output (image 1)
Expected database output (image 2): 36987-2480
Error obtained from print(result) - Image 3
(Since "Hi" is printed, in "view_nurse.py", it shows that "
if request.method == "POST"
is working.
However, "result" is not printed, showing that
result = request.POST.get("result")
is not working.)
Multiple POSTS in the same QR scan - Image 4
Do this in your <script> tag:
// Create a function to get the CSRF token
function getCookie(name) {
let cookie = document.cookie.match("(^|;) ?" + name + "=([^;]*)(;|$)");
return cookie ? cookie[2] : null;
}
function onScanSuccess(qrCodeMessage) {
document.getElementById("result").innerHTML =
'<span class="result">' + qrCodeMessage + "</span>";
// Call the function here
sendQrCode(qrCodeMessage);
}
async function sendQrCode(qrCode) {
const response = await fetch("/nurse_qrscan", {
method: "POST",
headers: {
"X-CSRFToken": getCookie("csrftoken"),
},
body: JSON.stringify({
result: qrCode,
}),
})
.then((response) => response.json())
.then((data) => {
// Do your thing here.
});
}
function onScanError(errorMessage) {
//handle scan error
}
var html5QrcodeScanner = new Html5QrcodeScanner("reader", {
fps: 10,
qrbox: 250,
});
html5QrcodeScanner.render(onScanSuccess, onScanError);
Let me know which part troubles you for further explanation.
Here is a breakdown.
First, you get the CSRF token from your form with the following:
function getCookie(name) {
let cookie = document.cookie.match("(^|;) ?" + name + "=([^;]*)(;|$)");
return cookie ? cookie[2] : null;
}
Second, after generating the qrcode in the onScanSuccess callback, you invoke sendQrCode function with the qr code as argument:
function onScanSuccess(qrCodeMessage) {
document.getElementById("result").innerHTML =
'<span class="result">' + qrCodeMessage + "</span>";
// Call the function here
sendQrCode(qrCodeMessage);
}
Third, you use Fetch to send a POST request to nurse_qrscan route:
async function sendQrCode(qrCode) {
const response = await fetch("/nurse_qrscan", {
method: "POST",
headers: {
// You pass the CSRF token generated from the function
"X-CSRFToken": getCookie("csrftoken"),
},
// Create an object with `result` as property
// and the `qrCode` as value.
// After that, convert it to JSON
body: JSON.stringify({
result: qrCode,
}),
})
....
It is a POST method because of method: "POST"
Following that, you write functionality to handle the data returned from your Django view:
async function sendQrCode(qrCode) {
...
.then((response) => response.json())
.then((data) => {
// Do your thing here.
});
}
Edit:
Could you elaborate on how the data returned in ".then((data) => { // Do your thing here}" can be handled? I don't quite understand what needs to be written in there?
In your nurse_qrscan view, you are returning something:
# import json at the top of the file
import json
def nurse_qrscan(request):
### Test! nurse: QR
if request.method == 'POST':
# parse the JSON data
data = json.load(request)
result = data.get('result')
print(result)
# Saving the result to database, nurse_QR
# c = connection.cursor()
# c.execute("INSERT INTO nurse_QR (output) VALUES ('{0}');".format(result))
return Action.success()
When it receives the POST request from fetch(), it will return Action.success. I can't tell if its JSON or if you want to do something with the returned value to the frontend. If you want to access the value in Frontend using JavaScript.
Assuming it is JSON, you can do this:
...
.then((response) => response.json())
.then((data) => {
console.log(data) // log the data returned from Django
});
}
In the line .then((response) => response.json()), The value returned from the view(if JSON), it is parsed into native JavaScript.
After the data is parsed, you can log it in the console or append in the DOM depending on your use case:
.then((data) => {
console.log(data) // log the data returned from Django
});
}

Method Not Allowed (POST) in ajax request with django

I am trying to pass the values of form data through ajax .And getting method not allowed error. I am trying to add comment in a blog post.
This is my form which is inside blog_detail page
<form id="commentform" class="commentform" method="post">
{% csrf_token %}
{%with allcomments.count as total_comments%}
<p>
{{total_comments}} comment{{total_comments|pluralize}}
</p>
{%endwith%}
<select name="blog" class="d-none" id="id_blog">
<option value="{{blog.id}}" selected="{{blog.id}}"></option>
</select>
<label class="small font-weight-bold">{{comment_form.parent.label}}</label>
{{comment_form.parent}}
<div class="d-flex">
<img class="avatar_comment align-self-center" src="{% for data in avatar%}{{data.avatar.url}}{%endfor%}" alt="">
{{comment_form.content}}
</div>
<div class="d-flex flex-row-reverse">
<button value="commentform" id="newcomment" type="submit" class="newcomment btn btn-primary">Submit</button>
</div>
</form>
And when I click the button it should call the ajax
$(document).on('click','#newcomment',function(e){
e.preventDefault();
var button =$(this).attr("value");
var placement = "commentform"
if (button=="newcommentform"){
var placement = "newcommentform"
}
$.ajax({
type: 'POST',
url: '{% url "website:addcomment" %}',
data: $("#" + button).serialize(),
cache: false,
sucess: function(json){
console.log(json)
$('<div id="" class="my-2 p-2" style="border: 1px solid grey"> \
<div class="d-flex justify-content-between">By ' + json['user'] + '<div></div>Posted: Just now!</div> \
<div>' + json['result'] + '</div> \
<hr> \
</div>').insertBefore('#' + placement);
},
error: function(xhr,errmsg,err){
}
});
})
This is my urls.py
path('blog/<int:blog_id>', BlogDetails.as_view(), name="blog_detail"),
path('addcomment/',addcomment, name="addcomment"),
and my views.py is:
class BlogDetails(View):
def get(self, request, blog_id):
query = request.GET.get('query')
if query:
return redirect(reverse('website:search') + '?query=' + query)
blog = Blog.objects.get(id=blog_id)
total_comment = Comment.objects.filter(blog=blog).count()
allcomments = blog.comments.filter(status=True)
blog_list = Blog.objects.all()
comment_form = NewCommentForm()
data = {
'blog': blog,
'blog_list': blog_list,
'total_comment': total_comment,
'comment_form': comment_form,
'allcomments': allcomments
}
return render(request, "blog_detail.html", data)
def addcomment(request):
if request.method == 'post':
comment_form = NewCommentForm(request.POST)
print(comment_form)
if comment_form.is_valid():
user_comment = comment_form.save(commit=False)
user_comment.user = request.user
user_comment.save()
result = comment_form.cleaned_data.get('content')
user = request.user.username
return JsonResponse({'result': result, 'user': user})
Please help me with this it is not calling addcomment view
If how I've interpreted your code is correct, it would probably work if changed your BlogDetails class to this:
class BlogDetails(View):
def get(self, request, blog_id):
query = request.GET.get('query')
if query:
return redirect(reverse('website:search') + '?query=' + query)
blog = Blog.objects.get(id=blog_id)
total_comment = Comment.objects.filter(blog=blog).count()
allcomments = blog.comments.filter(status=True)
blog_list = Blog.objects.all()
comment_form = NewCommentForm()
data = {
'blog': blog,
'blog_list': blog_list,
'total_comment': total_comment,
'comment_form': comment_form,
'allcomments': allcomments
}
return render(request, "blog_detail.html", data)
def post(self, request, *args, **kwargs):
return self.addcomment(request)
def addcomment(self, request):
comment_form = NewCommentForm(request.POST)
print(comment_form)
if comment_form.is_valid():
user_comment = comment_form.save(commit=False)
user_comment.user = request.user
user_comment.save()
result = comment_form.cleaned_data.get('content')
user = request.user.username
return JsonResponse({'result': result, 'user': user})
Because you are trying to POST to a view that doesn't have a post method defined.
Then you would need to remove addcomment from the URL you are calling and just post to whatever URL you are currently at.

How to Add Multiple Products to Shopify Cart with One Button Click

Here is the button's code:
{% assign p_annual = all_products[section.settings.paid_product_annual] %}
{% assign p_free = all_products[section.settings.free_product] %}
{% if section.settings.productlink1label != blank %}
<button class="btn"
type="submit"
name="paid-plan"
id="paid-plan-option-annual"
data-variant-id="{{ p_annual.selected_or_first_available_variant.metafields.subscriptions.discount_variant_id }}"
data-variant-interval-value="{{ p_annual.metafields.subscriptions.shipping_interval_frequency }}"
data-variant-interval-unit="{{ p_annual.metafields.subscriptions.shipping_interval_unit_type }}"
data-quickadd-id="{{ p_annual.selected_or_first_available_variant.id }}"
data-quickadd-properties
>
{{ p_annual.selected_or_first_available_variant.price | money_without_trailing_zeros }}{{ section.settings.productlink1label }}
</button>
{% endif %}
The code grabs the item by the ID and makes an AJAX request.
// quick add
_document.on('click', '[data-quickadd-id]', function() {
let _this = $(this);
loadingBarTrigger('start');
itemAdd(
_this.attr('data-quickadd-id'),
_this.attr('data-quickadd-properties'),
(_this.attr('data-quickadd-quantity'))
? _this.attr('data-quickadd-quantity')
: 1,
(!html.is('#cart')) ? true : false,
(html.is('#cart')) ? true : false
);
});
inside of cart function:
onst itemAdd = (variantId, properties, qty, openCart, reloadPage) => {
$.ajax({
type: 'POST',
dataType: 'html',
url: `/cart/add.js`,
data:
{
id: variantId,
quantity: qty,
properties: (properties)
? JSON.parse(properties) : null
},
error: function(data) {
console.error(data);
loadingBarTrigger('done');
},
success: function() {
loadingBarTrigger('move');
$.ajax({
url: '/cart',
dataType: 'html',
error: function(data) {
console.error(data);
loadingBarTrigger('done');
},
success: function(data) {
let minicartContent = $('#minicart-content');
let cartItemsHtml = $(data).find('#cart-content #cart-items').html();
// insert or prepend cart HTML
(minicartContent.find('#cart-items').length)
? minicartContent.find('#cart-items').html(cartItemsHtml)
: minicartContent.prepend(cartItemsHtml);
// remove giftbox content if exists
(minicartContent.find('#cart-giftbox .item-info').length)
? minicartContent.find('#cart-giftbox .item-info').remove()
: '';
loadingBarTrigger('done');
cartTotalUpdate();
// open cart
(openCart && !html.is('#cart'))
? minicartTrigger.trigger('click') : '';
(reloadPage)
? location.reload() : '';
}
});
}
});
}
I know this is possible with the AJAX API update last year. But I'm unsure how to implement it in my store. The data-variant-id only accepts one value if I'm not mistaken. And what's data-variant-id comes first gets precedence. I guess the main thing is that I'm unsure how to send json with the submit button.
Any ideas?
In a classic add product form, you can replace:
<input type="hidden" name="id" value="{{ product.selected_or_first_available_variant.id }}" disabled> with:
<input type="hidden" name="items[0][quantity]" value="1">
<input type="hidden" name="items[0][id]" value="ID_OF_YOUR_FIRST_PRODUCT_VARIANT">
<input type="hidden" name="items[1][quantity]" value="1">
<input type="hidden" name="items[1][id]" value="ID_OF_YOUR_SECOND_PRODUCT_VARIANT">
If you want to add the products in ajax, you just have to use the "FormData" object in the body of the request:
let addToCartForm = document.querySelector('form[action$="/cart/add"]');
let formData = new FormData(addToCartForm);
fetch(window.Shopify.routes.root + 'cart/add.js', {
method: 'POST',
body: formData
})
.then(response => {
return response.json();
})
.catch((error) => {
console.error('Error:', error);
});
I think you need to check and default Shopify documentation and make changes to the code according to the documentation.
Here into documentation they clearly mentioned how you can add multiple product using AJAX API.
https://shopify.dev/docs/themes/ajax-api/reference/cart
So you can check and update the code and past the multiple variants to items array like this demo code.
jQuery.post('/cart/add.js', {
items: [
{
quantity: quantity,
id: 1st ID
},
{
quantity: quantity,
id: 2nd ID
},
{
quantity: quantity,
id: 3rd ID
}
]
});

Django is_valid() returning false

I'm trying to validate a simple form with Django and it seems that it always returns false. I'm sending the value of the form via AJAX to the views.py and also printing the value in the Javascript and the view.py just to be sure it passed correctly.
The views file:
def change_alphabet(request):
cipher = CaesarCipher()
x = cipher.getListLetter()
y = cipher.getListLetter()
if request.is_ajax() and request.method == "GET":
print("Inside CHANGE")
formKey = caesarKey(request.GET or None)
print("Valid or not: %r " % formKey.is_valid())
integerKey = int(request.GET.get('the_key'))
print(integerKey)
if formKey.is_valid():
print(request.GET.get('the_key'))
integerKey = int(request.GET.get('the_key'))
y = cipher.setCipherLetters(integerKey)
context = { 'x': x,
'y': y,
'formKey': formKey,
}
return render(request, "content/alteredAlphabet.html", context)
else:
print(formKey.errors)
context = { 'x': x,
'y': y,
'formKey': formKey,
}
return render(request, "content/alteredAlphabet.html", context)
The form:
class caesarKey(forms.Form):
key = forms.DecimalField(max_value = 26, min_value = 1, initial = 1, required = True, error_messages={'required' : 'Please input a valid key number!'}, widget=forms.NumberInput(attrs={'class' : 'form-control', 'placeholder' : 'Key'}))
The Javascript:
$("#keyButtonId").on({
click: function() {
var variable = document.getElementById('id_key');
console.log(variable.value)
$.ajax({
url: "/alteredAlphabet",
type: "GET",
data: {
CSRF: 'csrf_token',
the_key: $('#id_key').val()
},
success: function(json) {
// $('#id_key').val('0');
// console.log(json);
$('#letterSection').fadeOut('slow', function() {
$('#letterSection').html(json);
$('#letterSection').fadeIn(3000);
});
//document.getElementById('letterSection').value = json;
console.log("FUNCTION CALLED!");
}
});
}
});
The error that is printed is:
<ul class="errorlist"><li>key<ul class="errorlist"><li>Please input a valid key number!</li></ul></li></ul>
UPDATE:
Template code for rendering the form:
<label for="id_key">
Key:
</label>
<form onsubmit="return false;" method="GET" id="key-form">
{% csrf_token %}
<div class="col-sm-2 col-xs-5">
{{ formKey.key }}
</div>
<button name="action" id="keyButtonId" class="btn btn-primary" value="key">Key</button>
</form>
{% if formKey.errors %}
<div class="alert alert-danger" role="alert">
<strong>{{ formKey.key.errors }}</strong>
</div>
{% endif %}
Why is it always returning false? Am I missing an additional phase of bounding the data?
You're passing your key data as the_key in the Ajax, but the form is expecting just key.

Refresh <div> element generated by a django template

How do I refresh a certain element within a django template?
Example:
{% if object.some_m2m_field.all %}
<h3>The stuff I want to refresh is below</h3>
<div id="the-div-that-should-be-refreshed">
{% for other_object in object.some_m2m_field.all %}
{{ other_object.title }}
{% endfor %}
</div>
{% endif %}
Lets say some other element in the page triggers a javascript that should refresh the div above. Is there a way to cause django to refresh this specific element within the template?
If not, I'll have to monkey-patch the div using regular JS or jQuery methods and not use the great power of django's template layer. Also, the above code is a simplification of the actual template, I use much of the template's power, so monkey-patching the resulting html will be a nightmare...
You could use an async request to fill the div element.
The async request is answered by Django using the template engine.
In this case, you would have to outsource the template code of the div element into a separate template file.
UPDATED WITH EXAMPLE:
Javascript:
For refreshing the view asynchronously, use JQuery for example:
$.ajax({
url: '{% url myview %}',
success: function(data) {
$('#the-div-that-should-be-refreshed').html(data);
}
});
Async View:
def myview(request):
object = ...
return render_to_response('my_template.html', { 'object': object })
Template:
{% for other_object in object.some_m2m_field.all %}
{{ other_object.title }}
{% endfor %}
You can have a look at eg. this Ajax with Django tutorial. Anyways as mentioned above you can always use django's template engine, no matter if the view is called in a normal or an ajax request! If you have to use ajax with django more frequently it makes sense to have a look at something like dajax, which is an ajax library for django (have a look at the tutorials there).
What i did was to put all the code into a set interval function, in this way I will render a location every 5 seconds
The base
setInterval(() => {
//code to execute
}, 5000);
Applying to my div
setInterval(() => {
console.log("interval")
$.ajax({
url: window.location.pathname,
async: false,
type: 'POST',
data: {
'action': 'graph_ubicacion',
'id': id
},
dataType: 'json',
}).done(function (data) {
//console.log("DEBUG 83 === ", data)
if (!data.hasOwnProperty('error')) {
//Proceso cuando se elije una ubicacion (después de tener una respuesta
dataCharArray = [
['Nombre', 'X', 'Y', 'Tipo'],
];
if (data.hasOwnProperty('todas')) {
data['todas'].forEach(function (elemento) {
dataCharArray[dataCharArray.length] = elemento;
//console.log("DEBUG 91 === ", elemento)
});
}
if (data.hasOwnProperty('target')) {
data['target'].forEach(function (elemento) {
dataCharArray[dataCharArray.length] = elemento;
console.log("DEBUG 102 === ", elemento, "\n")
console.log("DEBUG 102 === ", elemento[0], "\n")
console.log("DEBUG 102 === ", elemento[1], "\n")
console.log("DEBUG 102 === ", elemento[2], "\n")
console.log("DEBUG 102 === ", elemento[3], "\n")
});
}
if(data['todas'].length > 0 && data['target'].length > 0){
google.charts.load('current', {
'packages': ['corechart']
}
);
google.charts.setOnLoadCallback(drawSeriesChart);
}else{
if(data['todas'].length === 0 && data['target'].length === 0){
//MensajeAlerta("No hay Datos para mostrar");
console.log("No hay datos para mostrar")
}else{
if(data['todas'].length === 0){
MensajeAlerta("No hay Balizas para mostrar");
}
if(data['target'].length === 0){
MensajeAlerta("No hay Historial de datos de Pulseras para mostrar.");
}
}
}
return false;
} else {
MensajeError(data['error']);
}
}).fail(function (jqXHR, textStatus, errorThrown) {
MensajeError(textStatus + ': ' + errorThrown);
}).always(function (data) {
})
}, 5000);

Categories

Resources