Search code examples
javascriptpythonhtmldjangoqr-code

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) enter image description here

Expected database output (image 2): 36987-2480 enter image description here

Error obtained from print(result) - Image 3

enter image description here (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

enter image description here


Solution

  • 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
        });
    }