Tengo un modelo y en una función este modelo se está actualizando. Quiero mostrar los datos de este modelo de forma dinámica. Por lo tanto, los nuevos valores deberían mostrarse sin actualizar la página. ¿Cómo puedo hacerlo?
modelos.py
class MyLongProcess(models.Model): active_uuid = models.UUIDField('Active process', null=True, blank=True) name = models.CharField('Name', max_length=255) current_step = models.IntegerField('Current step', default=0) total = models.IntegerField('Total', default=0) @property def percentage_sending(self): # or it can be computed by filtering elements processed in celery with complete status return int((current_step / total) * 100)vistas.py
def setup_wizard(request): process = MyLongProcess.objects.create(active_uuid=uuid.uuid4(), name=name, total=100) functions.myClass(..., process=process) .... return render(request, 'setup_wizard.html', context)funciones.py
class myClass(): def __init__(self, ..., process): self.download_all(..., process=process) @app.task(bind=TRUE) def download_all(self, ..., process): .... for s in scans: .... process.current_step += 1 process.save() ...setup_wizard.html
<div class="progress-bar" role="progressbar" style="width: {{ my_model_object.percentage_sending }}%;" aria-valuenow="{{ my_model_object.percentage_sending }}" aria-valuemin="0" aria-valuemax="100">{{ my_model_object.percentage_sending }}% </div> Toda mi función funciona bien. Cuando miro MyLongProcess desde el administrador de Django y actualizo la página, los valores se actualizan. Solo quiero mostrarlo en la interfaz sin actualizar.
esto no es para lo que estaba destinado Django. Esencialmente, representa contenido HTML estático y eso es todo. lo que le gustaría hacer en una función que requiere mucho tiempo como esa es representar primero algún contenido inicial (digamos con un progreso de 0) y luego notificar a la interfaz de forma asíncrona. Esto se puede lograr de dos maneras. La primera forma es definitivamente más fácil de implementar, pero es un poco más difícil para los recursos, que es el sondeo. esencialmente, crea un punto final especial en su urls.py que, cuando se accede, le daría el porcentaje del trabajo que está buscando. entonces podría tener un código javascript que tendría setInterval( (js-code), 1000) para actualizar el progreso cada segundo. Solo para darle una descripción general de cómo se podría implementar esto:
document.addEventListener("DOMContentLoaded", function(event) { var myElement = document.getElementById('my-element'); var task_id = myElement.getAttribute('data-task_id'); setInterval(function() { var progressReq = new XMLHttpRequest(); progressReq.addEventListener("load", function() { myElement.setAttribute('aria-valuenow', this.responseText); }); progressReq.open("GET", "/progress-query/?task_id=" + task_id); progressReq.send(); }, 1000); });la solicitud HTTP realmente puede verse mucho mejor con la ayuda de jQuery, pero solo quería darle una idea de cómo podría verse esto.
Para que esto funcione, debe modificar la plantilla html para incluir la identificación de la siguiente manera:
<div ... data-task_id="some-task-id" />si desea publicar valores relacionados con el modelo aquí, tenga en cuenta que los hash para que no publique accidentalmente PK de la base de datos sin procesar o algo así.
El segundo enfoque, que es un poco más complejo de implementar, sería usar websockets. esto significa que cuando se inicie la interfaz, escuchará los eventos que se le envíen a través de la implementación del websocket del backend. De esta manera, podría actualizar el progreso casi en tiempo real, en lugar de cada segundo. En ambos enfoques, el código javascript tendría que acceder al elemento que desea actualizar, ya sea a través de var element = document.getElementById( ... ) (lo que significa que debe tener una identificación para empezar) o con la ayuda de jQuery. luego puede actualizar el valor así: element.setAttribute('aria-valuenow', 10) . Por supuesto, con la ayuda de bibliotecas como jQuery, su código puede verse mucho mejor que esto.
PD: no olvide (si utiliza el método de sondeo) interrumpir el ciclo setInterval una vez que el progreso llegue a 100 :-)