Как динамически отобразить данные модели в Html?

У меня есть модель, и в функции эта модель обновляется. Я хочу отображать данные этой модели динамически. Таким образом, новые значения должны отображаться без обновления страницы. Как я могу это сделать?

models.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)

views.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)

functions.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>

Все мои функции работают нормально. Когда я просматриваю MyLongProcess из Django admin и обновляю страницу, значения обновляются. Просто я хочу отобразить его во фронтенде без обновления.

Это не то, для чего был предназначен Django. По сути, он рендерит статический HTML-контент и все. Что вы хотели бы сделать в такой трудоемкой функции, как эта, так это сначала отрисовать некоторый начальный контент (допустим, с прогрессом 0), а затем асинхронно уведомить фронтенд. Это может быть реализовано двумя способами. Первый способ, безусловно, проще в реализации, но он немного сложнее по ресурсам - это опрос. По сути, вы создаете специальную конечную точку в вашем urls.py, которая, при обращении к ней, будет выдавать вам процент выполнения задания, которое вы ищете. Затем вы можете иметь код javascript, который будет setInterval( (js-code), 1000) обновлять прогресс каждую секунду. Просто чтобы дать вам представление о том, как это может быть реализовано:

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

HTTP-запрос действительно может выглядеть намного красивее с помощью jQuery, но я хотел просто дать вам представление о том, как это может выглядеть.

Для того чтобы это работало, вам придется изменить html-шаблон и включить в него id следующим образом:

<div ... data-task_id="some-task-id" />

если вы захотите опубликовать здесь значения, связанные с моделью, не забывайте хэшировать их, чтобы случайно не опубликовать необработанные PK базы данных или что-то подобное.

Второй подход, который немного сложнее в реализации, заключается в использовании вебсокета. Это означает, что когда фронтенд запускается, он будет слушать события, которые посылаются ему через вебсокет бэкенда. Таким образом, вы могли бы обновлять прогресс почти в реальном времени, а не каждую секунду. В обоих подходах код javascript должен получить доступ к элементу, который вы хотите обновить - либо через var element = document.getElementById( ... ) (что означает, что для начала у вас должен быть id), либо с помощью jQuery. затем вы можете обновить значение следующим образом: element.setAttribute('aria-valuenow', 10). Конечно, с помощью библиотек типа jQuery ваш код может выглядеть гораздо красивее, чем это.

p.s. не забудьте (если вы используете метод опроса) прервать цикл setInterval, как только прогресс достигнет 100 :-)

Вернуться на верх