简体   繁体   中英

Refresh a page without reloading with Django

I'm making a system to detect presence by QR Code with Django, and I need a way to display a image and text when a QR Code is detected without having to reaload the page, i saw something about HTMX but i couldn't do much with it. There isn't much in the internet about using a if statement to do this.

views.py

from datetime import datetime
from django.http import JsonResponse, StreamingHttpResponse
from django.shortcuts import render
import cv2
import numpy as np
from pyzbar.pyzbar import decode
from django.views.decorators import gzip
from .models import *

def camera_feed(request):
    stream = CameraStreamingWidget()
    frames = stream.get_frames()
    return StreamingHttpResponse(frames, content_type='multipart/x-mixed-replace; boundary=frame')

class CameraStreamingWidget:
    def __init__(self):
        self.camera = cv2.VideoCapture(int(os.environ.get('CAMERA')))
        self.media_path = os.path.join(os.getcwd(), "media", "images")
        
        # create "media/images" folder if doesn't exist
        if not self.media_path:
            os.mkdir(self.media_path)

    def get_frames(self):
        while True:
            # Capture frame-by-frame
            success, frame = self.camera.read()
            if not success:
                break
            else:
                ret, buffer = cv2.imencode('.jpg', frame)
                
                # Add text on top of the barcode if there is a barcode in the stream using opencv
                # convert camera frame to numpy array
                color_image = np.asanyarray(frame)

                # decode numpy array to check if there is a barcode in color_image
                # you can add a custom check here to verify if the qr code has right identifier information
                if decode(color_image):
                    for barcode in decode(color_image):
                        barcode_data = (barcode.data).decode('utf-8')

                        print(barcode_data)
                        # if barcode data exists
                        if barcode_data:

                            '''# save file as PNG if a QR code is detected
                            image = os.path.join(self.media_path, f"{barcode_data}.png")
                            cv2.imwrite(image, frame)
                            
                            # print info for debugging purpose
                            print('-'*50)
                            print('Saving image to media...')
                            print('-'*50)
                            print(f'Saved as: {image}')
                            print('-'*50)'''
                            
                            pts = np.array([barcode.polygon], np.int32)
                            pts = pts.reshape((-1,1,2))
                            # draw polylines on the barcode
                            cv2.polylines(
                                img=color_image,
                                pts=[pts],
                                isClosed=True,
                                color=(0,255,0),
                                thickness=3
                            )
                            pts2 = barcode.rect
                            # put text on top of polylines
                            barcode_frame = cv2.putText(
                                img=color_image,
                                text=barcode_data,
                                org=(pts2[0], pts2[1]),
                                fontFace=cv2.FONT_HERSHEY_SCRIPT_SIMPLEX,
                                fontScale=0.1,
                                color=(0,0,255),
                                thickness=2
                            )
                            # encode the new barcode_frame that has polylines and barcode data text
                            _, buffer_ = cv2.imencode('.jpg', barcode_frame)
                            # convert barcode_frame to bytes
                            barcode_frame = buffer_.tobytes()
                            # yield output stream with polylines and barcode data text
                            yield (b'--frame\r\n'
                                b'Content-Type: image/jpeg\r\n\r\n' + barcode_frame + b'\r\n\r\n')
                # else, yield the normal camera stream
                else:
                    frame = buffer.tobytes()
                    yield (b'--frame\r\n'
                           b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')



def detect(request):
    stream = CameraStreamingWidget()
    success, frame = stream.camera.read()
    if success:
        status = True
    else:
        status = False

    return render(request, 'detect_barcodes/detect.html', context={'cam_status': status})

HTML template

{% extends '../base.html' %}

{% load static %}

{% block content %}
<div class="row">
    <h2>Sistema de Presença de Aluno por QR Code</h2>
    <hr />
    <div class="col-md-6">
        {% if cam_status %}
        <h3>Status do fluxo da câmera: Ligada</h3>
        <img src="{% url 'camera_feed' %}" style="width: 540px; height: 400px;" />
        {% else %}
        <h3>Status do fluxo da câmera: a câmera não está acessível ou está ocupada</h3>
        <h5>Coisas para checar: </h5>
        <ul class="text-right list-inline">
            <li>Conexão USB?</li>
            <li>Número da câmera em seu arquivo .env?</li>
            <li>A câmera já está em uso?</li>
        </ul>
        {% endif %}
    </div>
</div>

<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>

<script>
    $("#btn_ReadQRCode").on("click", function (e) {
        console.log("Ajax request triggered.");
        e.preventDefault();
        $.ajax({
            type: "POST",
            url: "{% url 'camera_feed' %}",
            data: {
                csrfmiddlewaretoken: "{{ csrf_token }}",
                dataType: "json",
            },
            success: function (data) {
                if (data.barcode_data !== null && data.barcode_data !== '') {
                    console.log(data);
                    $("#txt_BarcodeData").html(data.barcode_data);
                    $("#lbl_LastModified").html(
                        "Last modified at: " + data.file_saved_at
                    );
                } else {
                    console.log(data);
                    $("#txt_BarcodeData").html("");
                    $("#lbl_LastModified").html("<h3><em>No data or file not found. Scan barcode again.</em></h3>");
                }
            },
            error: function () {
                console.log(error);
            }
        });
    });
</script>
{% endblock content %}

(Sorry for my bad english, i used the tradutor)

You're best bet would probably to look into POSTing forms using Ajax + Javascirpt/JQuery , That would allow you to Submit the form and refreshing.

I'm not 100% sure on how you'd return the picture in Ajax though.

I've worked with barcodes before and what I've done is generate them in a folder static/barcodes/encoded_barcode_text.png then serve them using an image tag using that URL. Then you could run a Cron/Scheduled Task to clear that directory at some point

you can use django channels to make async connection to the server using javascript websocket built in library,you can read more through this docs for basic usage of django channels

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM