I'm trying to get value of checkbox in Flask without a submit.
Here is my app.py:
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route('/', methods=['GET', 'POST'])
def index():
if request.form.get('c_check')=="0":
print('success: 0')
checked=''
elif request.form.get('c_check')=="1":
print('success: 1')
checked='checked'
return render_template('index.html')
Here is my JavaScript that toggles the checkbox:
function hello() {
if (document.querySelector('input').value=='0') {
document.querySelector('input').value='1'
console.log('value 1');
}
else {
document.querySelector('input').value='0'
console.log('value 0');
}
}
And here is my index.html:
<form method="post" action="">
<div class="form-check form-switch">
<input class="form-check-input btn-lg"
name="c_check"
value="0"
type="checkbox"
role="switch"
id="flexSwitchCheckChecked"
onclick="hello()"
>
<label class="form-check-label btn-lg"
for="flexSwitchCheckChecked"></label>
<input type="submit">
</div>
</form>
<script src="{{url_for('static', filename= 'js/hello.js')}}"></script>
I want to
Remove the submit button
When I click on the checkbox, Python should receive the checkbox value, 0 or 1.
The present code only returns 1 when I click the submit button. The solution should be that I remove the submit button entirely and have Python listen on the value change and print that in real time.
I'm open to socketio solution, but I don't know how to do it.
To do this, you'll want to add a listener to the input. A form submission with a full refresh would probably be poor UX, so we'll send an asynchronous request with JS to POST the data to the route, then read data from the response.
Here's a proof-of-concept demo that uses JSON all the way through, the standard for AJAX nowadays:
index.html:
<body>
<input type="checkbox" />
<div class="result"></div>
<script>
document
.querySelector("input")
.addEventListener("click", e => {
fetch("/", {
method: "POST",
headers: {
"Accept": "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({
c_check: Number(e.target.checked)
})
})
.then(res => {
if (!res.ok) {
throw Error(res.status);
}
return res.json();
})
.then(({data: {val}}) => {
console.log(val);
const res = document.querySelector(".result");
res.innerText = `client got: ${val}`;
})
.catch(err => console.error(err))
;
})
;
</script>
</body>
app.py:
from flask import (
Flask, jsonify, render_template, request
)
app = Flask(__name__)
#app.route("/", methods=["GET", "POST"])
def index():
if request.method == "GET":
return render_template("index.html")
val = request.json.get("c_check")
print(val)
return jsonify({"data": {"val": val}})
if __name__ == "__main__":
app.run(host="127.0.0.1", port=5000, debug=True)
You only need to change the client-side for this; use AJAX.
Here's the simplest example using pure JavaScript:
function ajaxRequest() {
const checked = document.getElementById("mycheckbox").checked;
console.log("Sending data to the server that the checkbox is", checked);
// Use the XMLHttpRequest API
const xhttp = new XMLHttpRequest();
xhttp.onload = function() {
console.log("Result sent to server!");
}
xhttp.open("POST", "/", true);
xhttp.send();
}
<label for="mycheckbox">Check or uncheck this box:</label>
<input id="mycheckbox" type="checkbox" onchange="ajaxRequest()" />
Obviously the example won't work because there is no server, but this is an example of AJAX with a checkbox once a user clicks a checkbox.
Related
I recode a Tutorial on Youtube.
Django, Python, HTML an Javascript.
Everthing works fine exept the window.location.reload() function.
I try some workarounds with
windows.reload(true),
window.href = window.href
location = self.location
and some more.
I have a hunch that the reload is executed before or during the code before the reload. But I do not know.
The goal is to send the data from the input to the database and only then refresh the page.
This ist the Code from the tutorial:
index.html (shortened)
<body>
<header>
<h1>Shoppinglist</h1>
<div id="input-field">
<label for="item-input">Was möchtest du einkaufen?</label>
<input type="text" name="item" id="item-input">
</div>
<button id="btn" onclick="addItem()">+</button>
</header>
<div id="item-table">
{% for row in all_items %}
<div class="list-item">
<input type="checkbox"> {{row.name}}
</div>
{% endfor %}
</div>
<script>
function addItem(){
let itemName = document.getElementById("item-input").value;
let formData = new FormData();
let token = '{{csrf_token}}';
formData.append('itemName', itemName);
formData.append('csrfmiddlewaretoken', token);
fetch('/mylist/', {
method: 'POST',
body: formData
});
window.location.reload();
};
</script>
</body>
</html>
views.py
from django.shortcuts import render
from .models import ShoppingItem
# Create your views here.
def mylist(request):
if request.method == 'POST':
print('Received date: ', request.POST['itemName'])
ShoppingItem.objects.create(name = request.POST['itemName'])
all_items = ShoppingItem.objects.filter(done = 0)
return render(request, 'index.html', {'all_items':all_items})
models.py
from django.db import models
from datetime import date
#Create your models here.
class ShoppingItem(models.Model):
creatDate = models.DateField (default=date.today)
name = models.CharField (max_length =200)
done = models.BooleanField(default=False)
def __str__(self):
return '(' + str(self.id) +') ' +self.name
Try this:
async function addItem() {
let itemName = document.getElementById("item-input").value;
let formData = new FormData();
let token = "{{csrf_token}}";
formData.append("itemName", itemName);
formData.append("csrfmiddlewaretoken", token);
await fetch("/mylist/", {
method: "POST",
body: formData,
});
window.location.reload();
}
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
});
}
I want to develop an interface that uploads a file with Vue js from my backend in django, I can't figure out the problem. but here is the error I got: "POST http://127.0.0.1:8000/upload/ 500 (Internal Server Error)"
here the class "upload" in view.py:
def upload(request):
obj = None
dict={}
if request.method == 'POST':
repo = Repository(username="fedoraAdmin",password="fedora2022")
obj = repo.get_object(type=FileObject)
obj.file.content = request.FILES['file']
obj.file.mimetype=request.FILES['file'].content_type
obj.file.label=request.FILES['file'].name
obj.label = request.POST['label']
obj.save()
dict=obj.index_data()
print(dict)
return JsonResponse(dict)
my form in forms.py:
class UploadForm(forms.Form):
label = forms.CharField(max_length=255, # fedora label maxes out at 255 characters
help_text='Preliminary title for the new object. 255 characters max.')
file = forms.FileField()
Finally, my vue js code:
<template>
<div class="container"> <h1 class="title mb-6">Uploader</h1> <div>
<form #submit.prevent="submitFile" enctype="multipart/form-data">
<input type="file" #change="uploadFile" ref="file">
<button>Upload!</button>
</form>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'archivage',
mounted() {
document.title = 'Archivage | fedora'
} ,
methods: {
uploadFile() {
this.file = this.$refs.file.files[0];
this.label=this.$refs.file.files[0].name
},
performUpload() {
const formData = {
label: this.label,
file: this.file}
axios
.post('/upload/',formData)
.then(response => {
console.log(response.data) ;
}) .catch(error => {
console.log(error)
})
},
submitFile: function(){
this.performUpload() },
}
}
</script>
I was wondering if any of you guys here knew how to fix this error, I have been dealing with it for quite a few hours, it has to do with posting json date (a date from a html date picker) to a backend model using the django web framework. Please let me know if my question is unclear.
ViewOrders.html
<form id="form">
<label for="start">Drop Off Date Selector:</label>
<br>
<input type="date" id="dropOffDate" name="drop_Off_Date"
min="2022-01-01" max="3000-12-31">
<button type="submit" value="Continue" class="btn btn-outline-danger" id="submit-drop-off-date" >Submit Drop Off Date</button>
</form>
<script type="text/javascript">
var form = document.getElementById('form')
form.addEventListener('submit', function(e){
e.preventDefault()
submitDropOffData()
console.log("Drop Off Date submitted...")
})
function submitDropOffData() {
var dropOffDateInformation = {
'dropOffDate':null,
}
dropOffDateInformation.dropOffDate = form.drop_Off_Date.value
var url = "/process_drop_off_date/"
fetch(url, {
method:'POST',
headers:{
'Content-Type':'application/json',
'X-CSRFToken':csrftoken,
},
body:JSON.stringify({'drop-off-date':dropOffDateInformation}),
})
.then((response) => response.json())
.then((data) => {
console.log('Drop off date has been submitted...')
alert('Drop off date submitted');
window.location.href = "{% url 'home' %}"
})
}
</script>
Views.py
def processDropOffDate(request):
data = json.loads(request.body)
DropOffDate.objects.create(
DropOffDate=data['drop-off-date']['dropOffDate'],
)
return JsonResponse('Drop off date submitted...', safe=False)
Models.py
class DropOffDate(models.Model):
dropOffDate = models.CharField(max_length=150, null=True)
def __str__(self):
return str(self.dropOffDate)
Errors
The fix to this was that I had created an object with the wrong field name so the Json repsonse was invalid.
class DropOffDate(models.Model):
dropOffDate = models.CharField(max_length=150, null=True)
def __str__(self):
return str(self.dropOffDate)
Changed to:
class DropOffDate(models.Model):
DropOffDate = models.CharField(max_length=150, null=True)
def __str__(self):
return str(self.DropOffDate)
I'm trying to integrate Stripe custom checkout https://stripe.com/docs/checkout#integration-custom with Flask and WTForms. My problem at the moment is the payment form doesn't seem to be posting so the credit card charge cannot be created.
It seems the form is recognised because the token is being posted to stripe's api with a 200 response:
XHRPOST
https://api.stripe.com/v1/tokens
[HTTP/2.0 200 OK 1444ms]
Form data
card[cvc] 123
card[exp_month] 10
card[exp_year] 20
card[name] dev#local.host
card[number] 4242424242424242
email dev#local.host
guid 4a6cfd25-8c4b-4d98-9dd2-9e9c1770e290
key pk_test_DVVO0zxtWjXSZx4yHsZGJxtv
muid c6b9d635-20de-4fc6-8995-5d5b2d165881
payment_user_agent Stripe+Checkout+v3+checkout-manhattan+ (stripe.js/9dc17ab)
referrer http://localhost:8000/subscription/index
sid 494d70dd-e854-497b-945b-de0e96a0d646
time_on_page 26657
validation_type card
However the token (and the form) is not being posted to my server to create the charge that stripe requires.
Here is the javascript code to load stripe custom checkout, which is in /index.html:
<script src="https://checkout.stripe.com/checkout.js"></script>
<form role="form" id = "payment_form" action="{{ url_for('billing.charge') }}" method="post">
{{ form.hidden_tag }}
<input type="hidden" id="stripeToken" name="stripeToken" />
<input type="hidden" id="stripeEmail" name="stripeEmail" />
<div class="form-group">
<div class="col-md-12 button-field" style = "text-align: center;">
<button type="confirm" id = 'confirm' onclick = "runStripe('https://checkout.stripe.com/checkout.js')" class="btn btn-default btn-responsive btn-lg">Confirm Order</button>
</div>
</div>
<script>
var handler = StripeCheckout.configure({
key: "{{ stripe_key }}",
locale: 'auto',
token: function(token) {
// token ID as a hidden field
var form = document.createElement("form");
form.setAttribute('method', "POST");
form.setAttribute('action', "{{ url_for('billing.charge') }}");
form.setAttribute('name', "payment-form");
var inputToken = document.createElement("input");
inputToken.setAttribute('type', "hidden");
inputToken.setAttribute('name', "stripeToken");
inputToken.setAttribute('value', token.id);
form.appendChild(inputToken);
// email as a hidden field
var inputEmail = document.createElement("input");
inputEmail.setAttribute('type', "hidden");
inputEmail.setAttribute('name', "stripeEmail");
inputEmail.setAttribute('value', token.email);
form.appendChild(inputEmail);
document.body.appendChild(form);
}
});
document.getElementById('confirm').addEventListener('click', function(e) {
// Open Checkout with further options:
handler.open({
name: 'Stripe.com',
description: '2 widgets',
amount: '{{ amount }}'
});
e.preventDefault();
});
// Close Checkout on page navigation:
window.addEventListener('popstate', function() {
handler.close();
});
</script>
<script>
document.getElementsByClassName("stripe-button-el")[0].style.display = 'none';
</script>
I have attempted a post method within the html tag with no success. I have also tried adding a form variable within the javascript token to post to my charge route, adapted from this question: Stripe Checkout Link onClick does not process payment
Here is my index and charge routes for reference:
#billing.route('/index', methods=['GET', 'POST'])
def index():
stripe_key = current_app.config.get('STRIPE_PUBLISHABLE_KEY')
amount = 1010
form = CreditCardForm(stripe_key=stripe_key)
return render_template('billing/index.html', stripe_key=stripe_key, form=form)
#billing.route('/charge', methods=['GET', 'POST'])
def charge():
if request.method == 'POST':
customer = stripe.Customer.create(
email = current_user,
source = request.form['stripeToken']
)
charge = stripe.Charge.create(
customer = customer.id,
amount = 2000,
currency = 'usd',
description = 'payment'
)
return render_template('charge.html', customer=customer, charge=charge)
I decided to change the token to jquery, which now seems to work perfectly and is far simpler:
<script>
var handler = StripeCheckout.configure({
key: "{{ stripe_key }}",
locale: 'auto',
token: function(token) {
$(document).ready(function(){
$("#stripeToken").val(token.id);
$("#stripeEmail").val(token.email);
$("#payment_form").submit();
})
</script>
In order for the jquery to be recognised, I also added the script for the jquery package at the top of the html file:
script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
Finally, for anone else who needs help in flask, here is my adjusted route:
#billing.route('/index', methods=['GET', 'POST'])
#handle_stripe_exceptions
#login_required
def index():
stripe_key = current_app.config.get('STRIPE_PUBLISHABLE_KEY')
amount = 1010
form = CreditCardForm(stripe_key=stripe_key, name=current_user.name, amount=amount )
if request.method == 'POST':
customer = stripe.Customer.create(
email='customer#example.com',
source=request.form['stripeToken']
)
charge = stripe.Charge.create(
customer=customer.id,
amount=amount,
currency='usd',
description='Flask Charge'
)
return render_template('billing/index.html', stripe_key=stripe_key, form=form)